J'essaie d'écrire un test unitaire pour un simple bean utilisé dans mon programme pour valider les formulaires. Le bean est annoté avec @Component
et a une variable de classe qui est initialisée en utilisant
@Value("${this.property.value}") private String thisProperty;
Je voudrais écrire des tests unitaires pour les méthodes de validation à l'intérieur de cette classe, cependant, si possible, je voudrais le faire sans utiliser le fichier de propriétés. Mon raisonnement derrière cela est que si la valeur que je tire du fichier de propriétés change, je voudrais que cela n'affecte pas mon cas de test. Mon scénario de test teste le code qui valide la valeur, pas la valeur elle-même.
Existe-t-il un moyen d'utiliser du code Java dans ma classe de test pour initialiser une classe Java et remplir la propriété Spring @Value à l'intérieur de cette classe, puis l'utiliser pour tester avec?
J'ai trouvé ce mode d' emploi qui semble proche, mais utilise toujours un fichier de propriétés. Je préfère que tout soit du code Java.
Réponses:
Si possible, j'essaierais d'écrire ces tests sans contexte Spring. Si vous créez cette classe dans votre test sans ressort, alors vous avez un contrôle total sur ses domaines.
Pour définir le
@value
champ, vous pouvez utiliser SpringsReflectionTestUtils
- il a une méthodesetField
pour définir les champs privés.@see JavaDoc: ReflectionTestUtils.setField (java.lang.Object, java.lang.String, java.lang.Object)
la source
org.springframework.test.util.ReflectionTestUtils.setField(classUnderTest, "field", "value");
@Value
annotation vers le paramètre constructeur. Cela rend le code de test beaucoup plus simple lors de l'écriture manuelle du code, et Spring Boot s'en fiche.Depuis Spring 4.1, vous pouvez définir des valeurs de propriété uniquement dans le code en utilisant des
org.springframework.test.context.TestPropertySource
annotations au niveau de la classe Tests unitaires. Vous pouvez utiliser cette approche même pour injecter des propriétés dans des instances de bean dépendantesPar exemple
Remarque: il est nécessaire d'avoir une instance de
org.springframework.context.support.PropertySourcesPlaceholderConfigurer
dans le contexte SpringEdit 24-08-2017: Si vous utilisez SpringBoot 1.4.0 et versions ultérieures, vous pouvez initialiser les tests avec
@SpringBootTest
et les@SpringBootConfiguration
annotations. Plus d'infos iciDans le cas de SpringBoot, nous avons le code suivant
la source
Ne pas abuser des champs privés obtenir / définir par réflexion
L'utilisation de la réflexion comme cela se fait dans plusieurs réponses est quelque chose que nous pourrions éviter.
Il apporte une petite valeur ici alors qu'il présente de multiples inconvénients:
@Value String field
. Demain, vous pouvez déclarer5
ou en10
faire partie dans cette classe et vous ne savez peut-être même pas que vous diminuez la conception de la classe. Avec une approche plus visible pour définir ces champs (comme le constructeur), vous y réfléchirez à deux fois avant d'ajouter tous ces champs et vous les encapsulerez probablement dans une autre classe et les utiliserez@ConfigurationProperties
.Rendez votre classe testable à la fois unitaire et en intégration
Pour pouvoir écrire à la fois des tests unitaires simples (c'est-à-dire sans conteneur Spring en cours d'exécution) et des tests d'intégration pour votre classe de composants Spring, vous devez rendre cette classe utilisable avec ou sans Spring.
L'exécution d'un conteneur dans un test unitaire lorsqu'il n'est pas requis est une mauvaise pratique qui ralentit les builds locaux: vous ne le voulez pas.
J'ai ajouté cette réponse car aucune réponse ici ne semble montrer cette distinction et ils s'appuient donc systématiquement sur un conteneur en cours d'exécution.
Je pense donc que vous devriez déplacer cette propriété définie comme un interne de la classe:
dans un paramètre constructeur qui sera injecté par Spring:
Exemple de test unitaire
Vous pouvez instancier
Foo
sans Spring et injecter n'importe quelle valeurproperty
grâce au constructeur:Exemple de test d'intégration
Vous pouvez injecter la propriété dans le contexte avec Spring Boot de cette manière simple grâce à l'
properties
attribut@SpringBootTest
:Vous pouvez utiliser comme alternative
@TestPropertySource
mais cela ajoute une annotation supplémentaire:Avec Spring (sans Spring Boot), cela devrait être un peu plus compliqué, mais comme je n'ai pas utilisé Spring sans Spring Boot depuis longtemps, je ne préfère pas dire une chose stupide.
En remarque: si vous avez plusieurs
@Value
champs à définir, les extraire dans une classe annotée avec@ConfigurationProperties
est plus pertinent car nous ne voulons pas d'un constructeur avec trop d'arguments.la source
final
, c'estprivate String final property
Si vous le souhaitez, vous pouvez toujours exécuter vos tests dans le contexte Spring et définir les propriétés requises dans la classe de configuration Spring. Si vous utilisez JUnit, utilisez SpringJUnit4ClassRunner et définissez une classe de configuration dédiée pour vos tests comme celui-ci:
La classe sous test:
La classe de test:
Et la classe de configuration pour ce test:
Cela dit, je ne recommanderais pas cette approche, je l'ai simplement ajoutée ici pour référence. À mon avis, la meilleure façon est d'utiliser Mockito runner. Dans ce cas, vous n'exécutez pas du tout de tests dans Spring, ce qui est beaucoup plus clair et plus simple.
la source
Cela semble fonctionner, bien que toujours un peu verbeux (j'aimerais encore quelque chose de plus court):
la source
@TestProperty
annotation.@Value
s, que la propriété correspondante soit définie ou non.L'ajout de PropertyPlaceholderConfigurer dans la configuration fonctionne pour moi.
Et en classe de test
la source