Découvrez comment intégrer facilement l'analyse statique, les tests unitaires et d'autres méthodes de test de logiciels C et C++ dans votre pipeline CI/CD. Inscrivez-vous pour la démo >>

Quand se moquer du code C/C++ des tests unitaires

Par Miroslaw Zielinski

26 juillet 2018

6  min lire

Les tests unitaires consistent à tester les unités isolées. Dans cet article, nous regardons 7 fois pour se moquer, y compris quelques questions utiles afin que vous puissiez vous guider à travers les tests unitaires C et C ++.

De combien d'isolement de test unitaire avons-nous besoin? C'est une question récurrente et importante fréquemment débattue lors du développement de tests unitaires pour C et C ++. Et je ne parle pas ici de l'isolement du collègue développeur, assis à côté de nous dans l'espace ouvert et battant le rythme de la musique depuis ses écouteurs (ce qui, d'ailleurs, est également très important lorsque nous voulons créer du bien code qualité). Je parle de l'isolement du code testé de son environnement environnant - ses soi-disant collaborateurs.

Avant de continuer, permettez-moi de clarifier une chose: lorsque vous discutez du stubbing et du mocking pour les langages C et C ++, il y a généralement une ligne tracée entre C et C ++ en raison des différences dans la couche de langage reflétées dans la complexité, les capacités et les attentes concernant les cadres moqueurs typiques. Avec Parasoft C / C ++test , la situation est légèrement différente car la plupart des fonctionnalités du framework sont disponibles pour les deux langues. Ainsi, lorsque je discuterai de ce sujet, je donnerai un exemple de test unitaire C ou C ++, et à moins que je ne marque spécifiquement quelque chose comme pris en charge uniquement pour C ou C ++, vous devez toujours supposer que des fonctionnalités spécifiques sont fournies pour les deux langages.

Obtenez tout ce dont vous avez besoin pour créer, exécuter et gérer des tests unitaires. Voir le test Parasoft C / C ++ en action.
Voir la Démo du Produit

Isoler ou ne pas isoler?

D'une part, le bon sens dicte que nous ne devons pas isoler à moins d'avoir une bonne raison pour cela. Au final, tester les vrais collaborateurs ne fait qu'augmenter notre pénétration de la base de code. Pourquoi devrions-nous abandonner une couverture de code supplémentaire et la possibilité de trouver un bogue? Eh bien, il semble qu'il y ait de bonnes raisons à cela - nous en discuterons bientôt.

D'un autre côté, un testeur d'unité orthodoxe dira que les tests unitaires consistent à tester les unités isolées et il doit rester ce qu'il est. Le test avec de vrais collaborateurs est du domaine de la phase d'intégration. C'est un fait bien connu qu'en incluant les vrais collaborateurs dans le périmètre de test, nous rendons nos tests plus bruyants. Les tests reposant sur de vrais collaborateurs réagiront non seulement aux modifications du code testé, mais également aux modifications des composants dépendants. Des tests plus bruyants rendent le processus de maintenance plus coûteux et génèrent beaucoup de distractions. À long terme, cette distraction devient généralement la principale raison d'abandonner votre pratique des tests unitaires.

Alors, quelle est la stratégie pour isoler le code testé? Compte tenu de ce qui précède, il est difficile de formuler une bonne règle pour déterminer quels collaborateurs doivent être ridiculisés afin de fournir une isolation appropriée du code testé. Du point de vue de l'efficience et de l'efficacité des tests, les deux approches «isoler autant que vous le pouvez» et «éviter l'isolement de test unitaire si possible» présentent des avantages et des inconvénients.

3 raisons simples de se moquer

Voici quelques situations plus évidentes:

1. Collaborateur non encore mis en œuvre ou en cours de développement

C'est simple. Nous n'avons pas le choix et nous avons besoin d'une mise en œuvre fictive. Le diagramme ci-dessous illustre cet environnement de test unitaire typique (SUT - système sous test, composant dépendant du DOC / collaborateur):

2. Indépendance matérielle

Pour les développeurs qui écrivent des applications de bureau, cette classe de problèmes peut sembler lointaine, mais pour les développeurs embarqués, l'indépendance matérielle des tests unitaires est un aspect important qui permet un haut niveau d'automatisation et d'exécution des tests sans avoir besoin de matériel. Un bon exemple ici serait une unité sous test interagissant avec le matériel GPS, s'attendant à ce qu'une certaine séquence de coordonnées de localisation soit fournie pour calculer la vitesse. Bien que ce soit une bonne idée de faire plus d'exercice, je ne peux pas imaginer que des testeurs courent avec un appareil pour simuler un mouvement, juste pour générer les entrées de test requises, chaque fois qu'une session de test unitaire est requise. À cette fin, cet exemple illustre à quel point le test GPS d'un appareil serait tardif dans le cycle de vie du développement si l'indépendance du matériel n'était pas possible pendant le développement.

3. Injection de défauts

L'injection d'erreurs à dessein est un scénario courant dans les tests. Cela peut être utilisé, par exemple, pour tester que l'allocation de mémoire a échoué ou pour voir si un composant matériel a échoué. Certains développeurs essaient de stimuler le vrai collaborateur dans la phase d'initialisation du test, afin qu'il réponde avec une erreur lorsqu'il est appelé à partir du code testé. Pour moi, ce n'est pas pratique et c'est généralement trop compliqué. Une fausse implémentation spécifique à un test, qui simule une erreur, est généralement un bien meilleur choix.

4 raisons moins simples de se moquer

Outre ces cas évidents où un collaborateur moqueur est toujours souhaité, il existe d'autres situations plus subtiles où les faux collaborateurs sont un bon choix. Si notre processus de test souffre de l'un des problèmes énumérés ci-dessous, cela indique qu'une meilleure isolation du code testé est nécessaire.

1. Les tests unitaires ne sont pas répétables

Il est difficile d'implémenter des tests stables qui dépendent d'une dépendance volatile. Ce qui se passe généralement dans de tels cas, c'est que nous recevons des résultats de test différents sans changer le code testé ou le code des tests. La transitoire peut être un effet du fait de s'appuyer sur des appels système ou sur un signal externe qui ne peut pas être contrôlé depuis l'intérieur du test. Un exemple classique est l'horloge système - si un scénario de test nécessite de réagir à certains moments dans le temps, l'automatisation est difficile à réaliser sans collaborateurs moqués qui ont un contrôle total sur les entrées indirectes du code testé.

2. Les environnements de test sont difficiles à initialiser

L'initialisation de l'environnement de test peut être très complexe. Simuler les vrais collaborateurs afin qu'ils fournissent des entrées fiables au code testé peut être une tâche ardue, voire impossible.

Les composants sont souvent interdépendants, et en essayant d'initialiser un module spécifique, nous pouvons finir par initialiser la moitié du système. Le remplacement des vrais collaborateurs par une fausse implémentation réduit la complexité de l'initialisation de l'environnement de test.

3. L'état du test est difficile à déterminer

Dans de nombreux cas, la détermination du verdict du test nécessite de vérifier l'état du collaborateur après l'exécution du test. Avec de vrais collaborateurs, c'est souvent impossible car il n'y a pas de méthode d'accès adaptée dans l'interface réelle du collaborateur pour interroger l'état après le test.

Le remplacement d'un vrai collaborateur par une maquette résout généralement le problème, et nous pouvons étendre la fausse implémentation avec toutes sortes de méthodes d'accès pour déterminer le résultat du test.

4. Les tests sont lents

Il y a des cas où une réponse du vrai collaborateur peut prendre un temps considérable. Il n'est pas toujours clair quand le délai devient inacceptable et quand l'isolement est nécessaire. Un délai de 2 minutes dans un essai est-il acceptable ou non? Il est souvent souhaitable de pouvoir exécuter des suites de tests aussi rapidement que possible, peut-être après chaque changement de code. Les retards importants dus aux interactions avec de vrais collaborateurs peuvent rendre les suites de tests trop lentes pour être pratiques. Les simulations de ces vrais collaborateurs peuvent être plus rapides de plusieurs ordres de grandeur et amener le temps d'exécution des tests à un niveau acceptable.

Questions utiles pour déterminer s'il faut se moquer ou non

Ainsi, lorsque vous écrivez un nouveau test unitaire C ou C ++ et décidez d'utiliser des collaborateurs originaux ou des implémentations simulées, considérez les quatre questions suivantes:

  1. Le vrai collaborateur est-il une source de risque pour la stabilité de mes tests?
  2. Est-il difficile d'initialiser le vrai collaborateur?
  3. Est-il possible de vérifier l'état du collaborateur après le test, de décider du statut du test?
  4. Combien de temps faudra-t-il au collaborateur pour répondre?

Si nous connaissons suffisamment bien le collaborateur pour répondre à toutes ces questions, alors c'est une décision facile dans un sens ou dans l'autre. Sinon, je suggérerais de commencer par le vrai collaborateur et d'essayer de répondre à ces quatre questions au fur et à mesure. En pratique, c'est l'approche que la plupart des praticiens du développement piloté par les tests (TDD) appliquent dans leur travail quotidien. Cela signifie que vous devez prendre soin de vos cas de test et les examiner attentivement jusqu'à ce qu'ils deviennent stables.

Le plus souvent, l'isolation des tests unitaires est compliquée par les dépendances de l'unité testée. Il existe des cas clairement souhaitables où se moquer d'un composant dépendant est nécessaire, mais aussi des situations plus subtiles. Dans certains cas, ce n'est pas clair et dépend du risque et de l'incertitude d'une dépendance dans l'environnement de test.

Obtenez tout ce dont vous avez besoin pour créer, exécuter et gérer des tests unitaires. Voir le test Parasoft C / C ++ en action.
Voir la Démo du Produit

Par Miroslaw Zielinski

Chef de produit pour les solutions de test embarquées de Parasoft, les spécialités de Miroslaw comprennent le C / C ++, les RTOS, l'analyse de code statique, les tests unitaires, la gestion de la qualité des logiciels pour les applications critiques pour la sécurité et la conformité des logiciels aux normes de sécurité.

Recevez les dernières nouvelles et ressources sur les tests de logiciels dans votre boîte de réception.