Tests unitaires de la technologie de test logiciel - méthode de test de style ingénieur (2)

Comment écrire des tests unitaires ?

Introduction à JUnit

Fondamentalement, chaque langage et framework dispose de bons frameworks et outils de tests unitaires, tels que JUnit de Java, ScalaTest de Scala, unittest de Python, Jest de JavaScript, etc. Les exemples ci-dessus sont basés sur JUnit, nous présenterons brièvement JUnit ci-dessous.

Chaque méthode annotée @Test dans JUnit est un test. @Ignore peut ignorer un test. @Before, @BeforeClass, @After, @AfterClass peuvent insérer certaines opérations courantes avant et après l'exécution du test, telles que l'initialisation et la libération des ressources, etc.

En plus de assertEquals, JUnit prend également en charge de nombreuses autres méthodes d'assertion. Par exemple assertNull, assertArrayEquals, assertThrows, assertTimeout, etc. De plus, vous pouvez également utiliser une bibliothèque d'assertions tierce telle que Spring's Assert ou AssertJ.

En plus de tester la logique de code commune, JUnit peut également effectuer des tests d'exception et des tests de temps. Le test d'exception consiste à tester qu'un certain morceau de code doit lever une exception spécifiée, et le test de temps consiste à tester que le temps d'exécution du code se situe dans une certaine plage.

Il est également possible de regrouper les tests. Par exemple, il peut être divisé en contractTest, mockTest et unitTest, et le test d'un certain groupe peut être spécifié par des paramètres.

Je ne vais pas trop vous présenter ici. Si vous souhaitez en savoir plus sur JUnit, vous pouvez consulter le tutoriel JUnit de la Geek Academy et d'autres supports. Les fonctions de base des autres frameworks de tests unitaires sont similaires.

Test d'utilisation Double

Dans un test unitaire restreint, nous testons uniquement l’unité elle-même. Même si nous écrivons un test unitaire généralisé, il peut toujours dépendre d'autres modules, tels que des méthodes d'autres classes, des appels de service tiers ou des requêtes de base de données, etc., ce qui nous rend impossible de tester de manière très précise le système ou le module testé. commodément. Ensuite, nous devons utiliser le test Double.

Si vous étudiez attentivement, le test Double est divisé en plusieurs types, tels que les nuls, les faux, etc. Mais je pense que nous devons seulement clarifier deux catégories, à savoir Stub et Mock.

Bout

Les stubs sont des objets qui contiennent des données prédéfinies et sont renvoyés à l'appelant lors des tests. Stub est souvent utilisé dans des scénarios dans lesquels nous ne souhaitons pas renvoyer de données réelles ou provoquer d'autres effets secondaires.

Le Stub Jar généré par notre test de contrat et qui peut être exécuté via le stubrunner Spring Cloud est un Stub. Nous pouvons laisser Stub renvoyer de fausses données prédéfinies, puis nous pouvons nous appuyer sur ces données dans des tests unitaires pour tester le code. Par exemple, nous pouvons laisser l'utilisateur interroger le Stub pour renvoyer l'utilisateur authentifié et l'utilisateur non authentifié en fonction de l'ID utilisateur dans le paramètre, puis nous pouvons tester la logique de traitement de l'appelant dans ces deux cas.

Bien entendu, le Stub n’est peut-être pas un service distant, mais une autre classe. Nous disons donc souvent que nous devons programmer sur l'interface, car de cette façon, nous pouvons facilement créer une implémentation Stub de l'interface pour remplacer la classe spécifique.

classe publique StubNameService implémente NameService {

public String get (String userId) {

renvoie « « Nom d'utilisateur fictif » » ;

}

}

classe publique UserServiceTest {

// UserService dépend de NameService et appellera sa méthode get

@Injecter

service utilisateur privé;

@Test

public void whenUserIdIsProvided_thenRetrievedNameIsCorrect() {

userService.setNameService (nouveau StubNameService());

String testName = userService.getUserName(""SomeId"");

Assert.assertEquals(«« Nom d'utilisateur fictif»», testName);

}

}

Cependant, il est très difficile d'implémenter de nombreux stubs de cette manière. Désormais, nous n'avons plus besoin de créer des stubs nous-mêmes, car il existe divers outils fictifs.

Se moquer

Les simulacres font référence à des objets qui peuvent enregistrer leurs informations d'appel. Dans les assertions de test, nous pouvons vérifier que les simulacres sont appelés comme prévu.

La différence entre Mock et Stub est que Stub ne fournit que certaines données, n'effectue pas de vérification ou effectue uniquement une vérification basée sur l'état ; Mock peut également effectuer une vérification basée sur le comportement d'appel en plus de faire ce que fait Stub. Par exemple, Mock peut vérifier que l'interface Mock est appelée exactement deux fois et que les paramètres de l'appel sont les valeurs attendues.

L'outil Mock le plus couramment utilisé en Java est Mockito. Regardons un exemple simple, le UserService suivant dépend de NameService. Lorsque nous testons UserService, nous voulons isoler NameService, afin de pouvoir créer un Mock NameService et l'injecter dans UserService (au printemps, nous n'avons besoin que d'utiliser les deux annotations @Mock et @InjectMocks pour le compléter)

classe publique UserServiceTest {

@InjectMocks

service utilisateur privé;

@Se moquer

service de noms privé nameService ;

@Test

public void whenUserIdIsProvided_thenRetrievedNameIsCorrect() {

Mockito.when(nameService.getUserName(""SomeId"").thenReturn(""Nom d'utilisateur fictif"");

String testName = userService.getUserName(""SomeId"");

Assert.assertEquals(«« Nom d'utilisateur fictif»», testName);

Mockito.verify(nameService).getUserName(""SomeId"");

}

}

Notez que la dernière ligne ci-dessus vérifie que le getUserName du nameService est appelé avec le paramètre ""SomeId"". Pour plus d'informations sur Mockito, veuillez vous référer à la documentation de Mockito (

http://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/Mockito.html)。

essai de contrat

Le test du contrat générera un stub pour chaque service, qui pourra être utilisé pour les tests unitaires/d'intégration de l'appelant. Par exemple, nous devons tester l'opération de réservation du service de réservation, et l'opération de réservation appellera le service utilisateur pour vérifier certaines informations de base de l'utilisateur, par exemple si le médecin est certifié ou non.

Par conséquent, nous pouvons laisser le stub de contrat renvoyer des données utilisateur dans différents états en transmettant différents identifiants utilisateur, vérifiant ainsi différentes procédures de traitement. Par exemple, un scénario de test pour un flux de rendez-vous normal pourrait ressembler à ceci.

@RunWith(SpringJUnit4ClassRunner.class)

@SpringBootTest@AutoConfigureStubRunner(repositoryRoot=""http://<nexus_root>"",

ids = {""com.xingren.service:user-client-stubs:1.0.0:stubs:6565""})classe publique BookingTest {

// BookingService appellera le service utilisateur, et effectuera différents traitements après avoir obtenu le statut d'authentification du médecin

@Injecter

service de réservation privé bookingService ;

@Test

public void testBooking() {

Formulaire BookingForm = nouveau BookingForm (

1,//ID docteur

1 // identifiant du planning

1001 ); // ID patient

BookVO res = bookingService.book(formulaire);

assertTrue(res.id > 0);

assertTrue(res.payStatus == PayStatus.UN_PAY);

}

}

Notez que l'annotation AutoConfigureStubRunner ci-dessus consiste à définir et à démarrer le Stub du service utilisateur. Bien sûr, lors des tests, nous devons définir la baseUrl de l'interface d'appel de service sur http://localhost:6565. Pour plus d’informations sur les tests contractuels, veuillez consulter l’article Explorer les tests d’intégration dans un environnement de microservices.

TDD

En termes simples, Test Driven Development, ou TDD. La souris à l'oreille gauche a écrit un article selon lequel TDD n'est pas aussi beau qu'il y paraît, j'ai donc directement cité son introduction.

Son processus de développement commence à partir du scénario de test des exigences fonctionnelles, ajoutez d'abord un scénario de test, puis exécutez tous les scénarios de test pour voir s'il y a des problèmes, puis réalisez les fonctions à tester par le scénario de test, puis exécutez le scénario de test. pour voir si des cas échouent, refactorisez le code et répétez les étapes ci-dessus.

En fait, le processus TDD strict n’est pas très pratique, et la souris de l’oreille gauche elle-même est également critique. Cependant, pour les modules avec des définitions d'interface claires, il est toujours avantageux d'écrire d'abord des tests unitaires, puis d'écrire le code d'implémentation. Parce que l’objectif est clair et que vous pouvez obtenir un retour immédiat.

Source de l'article : Les droits d'auteur du réseau appartiennent à l'auteur original

Le contenu ci-dessus n'est pas à des fins commerciales, s'il implique des problèmes de propriété intellectuelle, veuillez contacter l'éditeur, nous nous en occuperons immédiatement

Guess you like

Origin blog.csdn.net/xuezhangmen/article/details/132421937