2010-11-18 6 views
6

J'ai lu que les méthodes statiques ont tendance à être évitées lors de l'utilisation de TDD car elles ont tendance à être difficiles à simuler. Je trouve cependant que la chose la plus facile à tester est une méthode statique qui a une fonctionnalité simple. Vous n'avez pas besoin d'instancier des classes, vous encouragez des méthodes simples, faites une chose, soyez "autonome", etc.méthodes statiques et tests unitaires

Quelqu'un peut-il expliquer cet écart entre les meilleures pratiques TDD et la facilité pragmatique?

grâce, A

Répondre

14

Une méthode statique est facile à tester, mais quelque chose qui appelle directement une méthode statique est généralement pas facile à tester indépendamment de la méthode statique, il dépend. Avec une méthode non statique, vous pouvez utiliser une instance stub/mock/fake pour faciliter les tests, mais si le code que vous testez appelle des méthodes statiques, il est effectivement "câblé" à cette méthode statique.

+0

Je pense que le terme que vous recherchez car est étroitement couplé. –

+1

@Martin: Merci, je connais le terme, même si c'est plus général que ce que je voulais dire ici. Les termes couramment utilisés finissent souvent par perdre presque leur sens parce que les gens (ab) les utilisent tellement, alors j'ai choisi d'utiliser une métaphore ici dans l'espoir que cela soit plus clair. –

+0

Première écoute «câblée» au lieu de coupler étroitement. C'est absolument génial comment un changement de termes peut aider à la compréhension. – jrahhali

2

Il est facile de tester la méthode statique. Le problème est qu'il n'existe aucun moyen d'isoler votre autre code de cette méthode statique lors du test de l'autre code. Le code appelant est étroitement couplé au code statique.

Une référence à une méthode statique ne peut pas être raillée par de nombreux frameworks moqueurs et ne peut pas être surchargée.

Si vous avez une classe qui effectue beaucoup d'appels statiques, alors pour la tester, vous devez configurer l'état global de l'application pour tous ces appels statiques - la maintenance devient donc un cauchemar. Et si votre test échoue, alors vous ne savez pas quel bit de code a causé l'échec.

Se tromper, c'est l'une des raisons pour lesquelles de nombreux développeurs pensent que TDD n'a aucun sens. Ils ont mis en place un énorme effort de maintenance pour les résultats des tests qui indiquent seulement vaguement ce qui s'est mal passé. S'ils avaient seulement réduit le couplage entre leurs unités de code, alors la maintenance serait triviale et les résultats du test spécifiques.

3

La réponse à la question posée est, à mon avis, "Orienté Objet semble être tout ce que les gens de TDD pensent."

Pourquoi? Je ne sais pas. Peut-être qu'ils sont tous des programmeurs Java qui ont été infectés par la maladie de faire tout compter sur six couches d'indirection, l'injection de dépendance et les adaptateurs d'interface.

Les programmeurs Java semblent aimer rendre tout difficile à l'avance afin de «gagner du temps plus tard».

Je conseille d'appliquer certains principes Agile à votre TDD: Si cela ne cause pas de problème, ne le réparez pas. Ne pas trop concevoir.

En pratique, je trouve que si les méthodes statiques sont bien testées en premier, alors elles ne vont pas être la cause de bugs dans leurs appelants.

Si les méthodes statiques s'exécutent rapidement, elles n'ont pas besoin de simulation.

Si les méthodes statiques fonctionnent avec des éléments externes au programme, vous pouvez avoir besoin d'une méthode fictive. Dans ce cas, vous devez pouvoir simuler de nombreux types de comportement de fonction.

Si vous avez besoin de simuler une méthode statique rappelez-vous qu'il existe des façons de le faire en dehors de de la programmation OO. Par exemple, vous pouvez écrire des scripts pour traiter votre code source dans un formulaire de test qui appelle votre fonction fictive.Vous pouvez lier différents fichiers objets ayant différentes versions de la fonction dans les programmes de test. Vous pouvez utiliser les astuces de l'éditeur de liens pour remplacer la définition de la fonction (si elle n'a pas été insérée). Je suis sûr qu'il y a d'autres trucs que je n'ai pas énumérés ici.

+0

Je serais d'accord avec vous dans les cas simples. De nombreuses méthodes statiques sont de simples appels d'utilitaires qui sont statiques car ils n'ont pas d'état. Mais d'autres appels statiques font référence à des variables globales (statiques) ou à d'autres appels statiques, ce qui peut être très difficile à gérer dans un environnement de test unitaire. Vous devez vous assurer que l'état global est correct pour chaque exécution de test - ou bien vous obtenez un flakiness (tests qui fonctionnent de manière isolée mais échouent lorsque le reste de la suite s'exécute). Donc, ça peut être un can-de-worms mais je suis d'accord que vous devriez être pragmatique à ce sujet. – sheikhjabootie

0

Ce conseil est vrai pour la plupart .. mais pas toujours. Mes commentaires ne sont pas spécifiques C++ ..

  1. tests d'écriture pour les méthodes statiques (qui sont purs/fonctions sans état): à savoir le travail hors des entrées pour produire un résultat cohérent. par exemple. Ajouter ci-dessous - donnera toujours la même valeur donnée à un ensemble particulier d'entrées. Il y a aucun problème dans les tests d'écriture pour ceux-ci ou le code qui appelle de telles méthodes statiques pures.
  2. tests d'écriture pour les méthodes statiques consomment état statique: par ex. GetAddCount() ci-dessous. L'appeler dans plusieurs tests peut donner des valeurs différentes. Ainsi, un test peut potentiellement nuire à l'exécution d'un autre test - les tests doivent être indépendants. Nous devons donc maintenant introduire une méthode pour réinitialiser l'état statique de sorte que chaque test puisse démarrer à partir d'une table rase (par exemple quelque chose comme ResetCount()).
  3. Ecriture de tests pour le code qui accède aux méthodes statiques mais aucun accès au code source de la dépendance: dépend une fois de plus des propriétés des méthodes statiques elles-mêmes. Cependant, s'ils sont nuls, vous avez une dépendance difficile. Si la dépendance est un objet, vous pouvez ajouter un setter au type dépendant et définir/injecter un faux objet pour vos tests. Lorsque la dépendance est statique, vous pouvez avoir besoin d'un refactoring important avant de pouvoir exécuter les tests de manière fiable. (Par exemple Ajouter une dépendance moyenne homme objet que les délégués à la méthode statique. Le plugin maintenant un middle-man faux pour vos tests)

permet de prendre un exemple

public class MyStaticClass 
{ 
    static int __count = 0; 
    public static int GetAddCount() 
    { return ++__count; } 

    public static int Add(int operand1, int operand2) 
    { return operand1 + operand2; } 

    // needed for testability 
    internal static void ResetCount() 
    { 
    __count = 0; 
    } 
} 

... 

//test1 
MyStaticClass.Add(2,3);  // => 5 
MyStaticClass.GetAddCount(); // => 1 

// test2 
MyStaticClass.Add(2,3); // => 5 
//MyStaticClass.ResetCount(); // needed for tests 
MyStaticClass.GetAddCount(); // => unless Reset is done, it can differ from 1