web-dev-qa-db-fra.com

Qu'est-ce que cela fait: @RunWith (SpringJUnit4ClassRunner.class)

Que fait cette annotation?
Quand voudrais-je l'utiliser?
Quand ne voudrais-je pas l'utiliser?

@RunWith(SpringJUnit4ClassRunner.class)

Je peux trouver plus d'utilisations de cela lorsque je Google et ne trouve pas une explication 101 quant à ce que cette annotation est censée me communiquer ou quand/pourquoi je l'utiliserais?

35
Jay Vee

L'annotation est utilisée pour configurer un test unitaire qui a nécessité l'injection de dépendances de Spring.

De Spring Reference - 10. Unit Testing :

10.1 Création d'une classe de test unitaire

Pour que le test unitaire exécute un travail par lots, la structure doit charger ApplicationContext du travail. Deux annotations sont utilisées pour déclencher ceci:

@RunWith (SpringJUnit4ClassRunner.class): indique que la classe doit utiliser les fonctionnalités JUnit de Spring.

@ContextConfiguration (locations = {...}): indique quels fichiers XML contiennent ApplicationContext.

15
Ricardo Veguilla

Si vous utilisez des annotations plutôt que des fichiers XML, alors toute classe que vous testez unitaire qui nécessite une injection de dépendance Spring doit être placée dans l'annotation @ContextConfiguration. Par exemple:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = FooManager.class)
class FooManagerTest {

    @Autowired
    FooManager fooManager;

Maintenant, lorsque vous utilisez fooManager dans un test unitaire, il aura une configuration de contexte Spring pour cela.

Si fooManager les fils automatiques dans les beans, les classes de ces beans doivent également être dans l'annotation @ContextConfiguration. Donc, si le FooManager bean passe automatiquement dans un bean FooReporter:

@ContextConfiguration(classes = {FooManager.class, FooReporter.class})

Si les beans qui fooManager auto-fils dans l'état contiennent, alors vous voudrez probablement réinitialiser l'état de ces beans pour chaque test. Dans ce cas, vous pouvez ajouter l'annotation @DirtiesContext À votre classe de test:

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)

Si le fooManager ou l'un de ses beans câblés automatiquement lit la configuration Spring, vous devez ajouter une liste initializers à l'annotation @ContextConfiguration, Qui contient le ConfigFileApplicationContextInitializer classe:

@ContextConfiguration(classes = FooManager.class, initializers = ConfigFileApplicationContextInitializer.class)
3
Joman68

Pour répondre au moment où vous voudriez et ne voudriez pas l'utiliser une partie de la question.

Quand utiliser SpringJUnit4ClassRunner

IMO SpringJUnit4ClassRunner doit être utilisé avec parcimonie. Il y a un surcoût important lié au démarrage d'un conteneur Spring pour exécuter un test unitaire.

J'utilise généralement SpringJUnit4ClassRunner pour tester:

  • que les composants sont injectés (auto-câblés) comme prévu
  • que les données de configuration sont injectées comme prévu

Lorsque vous injectez des composants, des problèmes peuvent survenir si le @Qualifier l'annotation n'est pas utilisée ou n'est pas utilisée correctement, par exemple.

Lors du chargement de la configuration à partir de plusieurs fichiers yaml, vous souhaiterez peut-être tester la fusion des cartes comme prévu, avec les remplacements appropriés.

À tout le moins, j'ai toujours un simple test SpringJUnit4ClassRunner pour vérifier que le conteneur Spring démarre correctement.

Quand ne pas utiliser SpringJUnit4ClassRunner

Je n'utiliserais pas SpringJUnit4ClassRunner pour tester la fonctionnalité non liée à Spring dans mon code en cours de test. Ce qui, selon mon expérience, signifie la plupart des fonctionnalités.

Cela signifie donc que tous les composants câblés automatiquement et les données de configuration injectées doivent être simulés. Cela peut signifier un peu de code d'installation pour vos tests unitaires. Cependant, ce code d'installation ne doit être écrit qu'une seule fois pour tous les tests de votre classe sous test. Il est également beaucoup plus rapide d'exécuter des tests unitaires avec des composants simulés.

Je garde la moquerie simple et utilise Spock pour me moquer des composants. Exemple de code groovy:

import spock.lang.Specification

class FooManagerTest extends Specification {

  FooManager cut

  void createMockFooReporter() {
    FooReporter mockFooReporter = Mock(FooReporter)
    mockFooReporter.fooFormatter = Mock(FooFormatter)
  }

  void setup() {
    cut = new FooManager()
    cut.fooReporter = createMockFooReporter()
  }

  void "Basic test"() {
     // Do a basic test using 'cut'
  }

}

Dans cet exemple, la classe testée FooManager a un FooReporter autowired qui contient lui-même un FooFormatter autowired.

2
Joman68