2017-08-16 4 views
1

J'essaie d'écrire des tests pour une classe qui a une valeur de champ injectée à partir d'un fichier de propriétés. J'essaie d'utiliser l'annotation TestPropertySource pour obtenir des valeurs lors de l'exécution de tests TestNG, mais il semble ignorer mon fichier de propriétés.Test TestNG n'utilisant pas TestPropertySource pour l'injection de @Value

Il y a des dizaines de questions similaires, que j'ai essayé de lire attentivement et d'essayer leurs implémentations lorsque c'est possible. Il semble ma question est encore un peu différent cependant, voici pourquoi:

Qu'est-ce que vous devez faire pour obtenir une unité sous test avec @Value champs annotés fixés avec leurs biens? Puis-je en quelque sorte demander au printemps de me fournir des instances de ma classe au lieu de les utiliser moi-même?

Voici un repro minimal.

foo.java

package nl.jeroenheijmans.stackoverflow.testngprops; 

import org.springframework.beans.factory.annotation.Value; 
import org.springframework.stereotype.Component; 

@Component 
public class Foo { 
    @Value("${my.prop}") 
    private String myProp; 

    public String ExposeProp() { 
     return myProp; 
    } 
} 

FooTest.java

package nl.jeroenheijmans.stackoverflow.testngprops; 

import org.springframework.test.context.TestPropertySource; 
import org.testng.Assert; 
import org.testng.annotations.Test; 

@TestPropertySource("classpath:application.properties") 
public class FooTest { 
    @Test 
    public void sanityCheck(){ 
     Foo foo = new Foo(); 
     Assert.assertNotNull(foo); // Success! 
    } 

    @Test 
    public void testProperty() { 
     Foo foo = new Foo(); 
     Assert.assertEquals(foo.ExposeProp(), "checkcheck"); // Fail! 
    } 
} 

application.properties (à la fois dans le dossier main et test)

my.prop=checkcheck 

Main.java

package nl.jeroenheijmans.stackoverflow.testngprops; 

import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.boot.builder.SpringApplicationBuilder; 
import org.springframework.boot.web.support.SpringBootServletInitializer; 
import org.springframework.context.annotation.PropertySource; 

@SpringBootApplication 
@PropertySource(value = {"classpath:application.properties"}) 
public class Main extends SpringBootServletInitializer { 
    public static void main(String... args) { 
     SpringApplication.run(Main.class, args); 
    } 

    @Override 
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 
     return application.sources(Main.class); 
    } 
} 

pom.xml

<?xml version="1.0" encoding="UTF-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>nl.jeroenheijmans.stackoverflow</groupId> 
    <artifactId>testngprops</artifactId> 
    <version>1.0-SNAPSHOT</version> 

    <dependencies> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-actuator</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-web</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-test</artifactId> 
      <scope>test</scope> 
     </dependency> 
     <dependency> 
      <groupId>org.mockito</groupId> 
      <artifactId>mockito-all</artifactId> 
      <scope>test</scope> 
     </dependency> 
     <dependency> 
      <groupId>org.testng</groupId> 
      <artifactId>testng</artifactId> 
      <scope>test</scope> 
     </dependency> 
    </dependencies> 

    <dependencyManagement> 
     <dependencies> 
      <dependency> 
       <groupId>org.springframework.boot</groupId> 
       <artifactId>spring-boot-dependencies</artifactId> 
       <version>${org.springframework.boot.version}</version> 
       <type>pom</type> 
       <scope>import</scope> 
      </dependency> 
      <dependency> 
       <groupId>org.testng</groupId> 
       <artifactId>testng</artifactId> 
       <version>${testng.version}</version> 
       <scope>test</scope> 
      </dependency> 
      <dependency> 
       <groupId>org.mockito</groupId> 
       <artifactId>mockito-all</artifactId> 
       <version>${mockito.version}</version> 
       <scope>test</scope> 
      </dependency> 
     </dependencies> 
    </dependencyManagement> 

    <build> 
     <plugins> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-compiler-plugin</artifactId> 
       <version>${maven.compiler.version}</version> 
       <configuration> 
        <source>${java.version}</source> 
        <target>${java.version}</target> 
       </configuration> 
      </plugin> 
     </plugins> 
    </build> 

    <properties> 
     <java.version>1.8</java.version> 
     <maven.compiler.version>3.5</maven.compiler.version> 
     <org.springframework.boot.version>1.5.1.RELEASE</org.springframework.boot.version> 
     <testng.version>6.9.10</testng.version> 
     <mockito.version>1.9.5</mockito.version> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
    </properties> 
</project> 

Répondre

2

Voilà comment je résolu ce problème.

En résumé, je crois qu'il vous manquait la partie d'extension org.springframework.test.context.testng.AbstractTestNGSpringContextTests et l'utilisation de l'injection de dépendance pour l'objet Foo via l'annotation @Autowire. Puisque vous instanciez l'objet Foo, les valeurs n'étaient pas injectées dedans, ce qui explique pourquoi les assertions échouaient.

Principal.java

package com.rationaleemotions.stackoverflow.qn45716815; 

import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; 
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; 
import org.springframework.boot.builder.SpringApplicationBuilder; 
import org.springframework.boot.web.support.SpringBootServletInitializer; 
import org.springframework.context.annotation.PropertySource; 

@SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}) 
@PropertySource(value = {"classpath:application.properties"}) 
public class Main extends SpringBootServletInitializer { 
    public static void main(String... args) { 
     SpringApplication.run(Main.class, args); 
    } 

    @Override 
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 
     return application.sources(Main.class); 
    } 
} 

La raison de l'utilisation @SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}) se trouve dans ce fil: Mongo tries to connect automatically to port 27017(localhost)

Mise à jour:Exclusion de configuration est facultative et Mongo vous n'avez pas besoin de faire cela, si vous avoir un projet qui est correctement configuré pour Mongo.

Voilà comment le FooTest.java ressemble

package com.rationaleemotions.stackoverflow.qn45716815; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.test.context.SpringBootTest; 
import org.springframework.test.context.TestPropertySource; 
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; 
import org.testng.Assert; 
import org.testng.annotations.Test; 

@TestPropertySource("classpath:application.properties") 
@SpringBootTest 
public class FooTest extends AbstractTestNGSpringContextTests{ 
    @Autowired 
    private Foo foo; 

    @Test 
    public void sanityCheck() { 
     Assert.assertNotNull(foo); 
    } 

    @Test 
    public void testProperty() { 
     Assert.assertEquals(foo.ExposeProp(), "checkcheck"); 
    } 
} 

Voici comment mes dépendances de Maven ressemble

<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-web</artifactId> 
    <version>1.5.6.RELEASE</version> 
    <exclusions> 
     <exclusion> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-logging</artifactId> 
     </exclusion> 
    </exclusions> 
</dependency> 
<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-test</artifactId> 
    <version>1.5.6.RELEASE</version> 
    <scope>test</scope> 
</dependency> 

La raison de l'ajout d'une exclusion au printemps-démarrage démarreur-logging Vous trouverez ici: Disable Logback in SpringBoot

Mise à jour:Exclusion de logback est facultative et que vous ne devez faire cela, si vous avez un projet qui est correctement configuré pour travailler avec logback.

est ici la sortie quand j'ai couru ce test:

objc[36167]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/bin/java (0x1026784c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x1027404e0). One of the two will be used. Which one is undefined. 
log4j:WARN No appenders could be found for logger (org.springframework.test.context.BootstrapUtils). 
log4j:WARN Please initialize the log4j system properly. 

    . ____   _   __ _ _ 
/\\/___'_ __ _ _(_)_ __ __ _ \ \ \ \ 
(()\___ | '_ | '_| | '_ \/ _` | \ \ \ \ 
\\/ ___)| |_)| | | | | || (_| | )))) 
    ' |____| .__|_| |_|_| |_\__, |//// 
=========|_|==============|___/=/_/_/_/ 
:: Spring Boot ::  (v1.5.6.RELEASE) 


=============================================== 
Default Suite 
Total tests run: 2, Failures: 0, Skips: 0 
=============================================== 
+0

Thx pour la réponse, va vérifier dans un peu. (Je suis déconcerté par la façon dont Mongo apparaît, n'a pas réalisé qu'il ya des dépendances liées mongo dans la chaîne quelque part.) – Jeroen

+0

@Jeroen - S'il vous plaît ne pas oublier d'accepter la réponse, si elle a répondu à votre question. –

+0

Le '' @ SpringBootTest' + ... + étend AbstractTestNGSpringContextTests' '@ propriété AutoWired' a fait l'affaire. Les trucs de Mongo, les trucs de Logback et les trucs de Log4j n'étaient pas nécessaires pour passer mes tests. – Jeroen