2010-05-04 3 views
6

Moi et mes collègues avons eu un peu de désaccord hier soir au sujet des tests unitaires dans notre application PHP/MySQL. La moitié d'entre nous ont soutenu que lorsque vous testez une fonction dans une classe, vous devez vous moquer de tout ce qui se trouve en dehors de cette classe et de ses parents. L'autre moitié a fait valoir que vous NE DEVRIEZ PAS vous moquer de tout ce qui est une dépendance directe de la classe non plus.Tests unitaires - objectif fondamental?

L'exemple spécifique était notre mécanisme de journalisation, qui est passé à travers une classe Logging statique, et nous avons eu un certain nombre d'appels Logging :: log() à divers endroits dans notre application. La première moitié d'entre nous a dit que le mécanisme de journalisation devrait être truqué (faux) parce qu'il serait testé dans les tests de l'unité de journalisation. La deuxième moitié d'entre nous a soutenu que nous devrions inclure la classe Logging originale dans notre test unitaire de sorte que si nous modifions notre interface de journalisation, nous serons en mesure de voir si cela crée des problèmes dans d'autres parties de l'application mettre à jour l'interface d'appel. Donc, je suppose que la question fondamentale est: est-ce que les tests unitaires servent à tester la fonctionnalité d'une seule unité dans un environnement fermé, ou à montrer les conséquences de changements à une seule unité dans un environnement plus large? Si c'est l'un d'entre eux, comment accomplissez-vous l'autre?

+0

+1 C'est une bonne question, car elle expose quelque chose que beaucoup de gens confondent avec les tests unitaires. – Fenton

Répondre

11

Vous et vos collègues avez découvert la différence entre les tests unitaires et les tests d'intégration. Se moquer de tout serait fait pour le premier; on ne se moquerait pas des dépendances pour ce dernier. Bien sûr, lorsque vous tracez la ligne de granularité est aussi subjective, mais au niveau de détail le plus fin pour les tests unitaires, vous ne devriez pas vous soucier de quoi que ce soit en dehors du sujet spécifique de chaque test.

+2

Parfois, lorsque vous décidez que quelque chose est testé et fait partie de * la plate-forme *, vous pouvez décider de l'utiliser même à l'intérieur de tests unitaires. Par exemple, vous ne feriez pas une fausse bibliothèque standard ou peut-être pas un framework de confiance pour fonctionner correctement. Si vous pouvez vous permettre une telle confiance, cela pourrait épargner quelques lignes de code. –

+0

Oui, tout à fait vrai - généralement, les moqueries sont réservées aux composants qui sont développés dans le cadre de votre projet, mais ce n'est pas la chose actuellement testée. – Amber

+0

+1 - Convenir que les tests unitaires sont effectués isolément et devraient couvrir 100% de votre code. Les tests d'intégration sont effectués à l'unisson et la couverture n'a pas besoin d'être aussi élevée - vous testez l'interaction plutôt que la fonction. http://www.enhance-php.com/Content/About-Unit-Testing/ – Fenton

1

Les mots donnent quelques conseils quant à la réponse:

unité

signifie 1: vous essayez de tester une chose. Vous pouvez simuler des dépendances comme la structure de journalisation lorsque ce n'est pas l'objectif principal de vos tests. La façon dont l'unité testée interagit avec ses dépendances fait souvent partie du cas de test, et le fait de se moquer rend cela beaucoup plus facile. L'intégration signifie plus d'une chose: vous essayez de combiner plus d'une chose ensemble un test dans son ensemble. La simulation joue un rôle moindre, mais elle peut néanmoins être utile pour émuler les personnes à charge qui seraient difficiles à configurer dans le scénario de test.

Je dirais que l'argument pour ne pas se moquer du système de journalisation dans les tests unitaires, pour voir si les changements cassent quelque chose est assez faible. Si quelque chose est cassé dans le système de journalisation, alors cela devrait être attrapé par un test unitaire échoué pour le système de journalisation. Garder les tests unitaires simples, clairs et focalisés est une bonne règle empirique. Yuu a besoin de cette base de simplicité pour étendre la portée des tests. Les tests d'intégration peuvent rapidement devenir complexes, surtout lorsqu'ils sont utilisés comme substituts aux tests unitaires manquants - c'est comme «tester à distance» et plus on s'éloigne d'un composant, plus il est difficile de tester et de diagnostiquer les échecs. Tester une dépendance lointaine à l'aide d'un test unitaire est comme une personne essayant de faire fonctionner la télé-télécommande de l'autre côté de la pièce à l'aide d'une canne à pêche.

5

Le test unitaire est comme tester un seul composant dans un appareil électronique.

Si vous souhaitez tester un seul transistor dans un ampli de guitare, vous ne devez pas brancher de guitare, augmenter le volume et vérifier les sons émis. Ce serait stupide. Pour vérifier un transistor, vous devez brancher l'équipement jusqu'aux fils de que le transistor et mesurer seulement ses entrées et sorties.À un certain moment, vous faites tout tester (guitare fait du bruit, etc.), mais c'est différent de tester un seul transistor.

0

@David, je vois que les tests unitaires pour vous font le travail qu'il est censé faire.

Vous réfléchissez sur la conception de votre logiciel. De la façon dont vous posez votre question sur l'environnement fermé par rapport à l'environnement ouvert, cela m'amène à croire que vous êtes sur le point de devoir répondre à la question du test basé sur l'état ou du comportement pour votre code.

Il n'y a pas de règle rapide pour savoir quand utiliser un objet réel ou un faux pour tester un appareil. UNIQUEMENT PRINCIPES DIRECTEURS! Le problème des tests unitaires avec un vrai objet Logging est que les tests pour cet objet seront non seulement dans les tests unitaires pour l'enregistreur mais aussi dans les tests unitaires pour les objets utilisant l'enregistreur. Donc, si vous avez 20 objets qui utilisent l'enregistreur et que vous changez l'interface de l'enregistreur, il y aura au moins 21 tests échoués. Cela peut être assez douloureux lors de la refactorisation. Mais d'un autre côté, si vous n'utilisez pas la classe logger dans les tests unitaires de 20 objets et que vous changez l'interface de l'enregistreur, un seul test échoue et 20 autres tests unitaires deviennent verts, même s'ils échouent en production.

Le seul point que je peux vraiment vous donner est que vous n'avez pas les bonnes abstractions en place. Vous voudrez peut-être regarder SOLID. Ceux-ci devraient être principes directeurs.

Rappelez-vous quand des questions se posent comme si vous demandiez que ce soit le code qui vous donne votre avis. Tenez compte de cette rétroaction. Cela vous épargnera beaucoup de douleur plus tard.