2008-09-18 6 views
4

Dans une question récente sur le stubbing, de nombreuses réponses suggèrent des interfaces C# ou des délégués pour implémenter des stubs, mais one answer suggère d'utiliser la compilation conditionnelle, en conservant la liaison statique dans le code de production. Cette réponse a été modulée -2 au moment de la lecture, donc au moins 2 personnes ont vraiment pensé que c'était une réponse mauvaise. Peut-être que l'abus de DEBUG était la raison, ou peut-être l'utilisation d'une valeur fixe au lieu d'une validation plus étendue. Mais je ne peux m'empêcher de me demander:La compilation conditionnelle est-elle une stratégie de simulation/tronçon valide pour les tests unitaires?

L'utilisation de la compilation conditionnelle est-elle une technique inappropriée pour implémenter des talons de test unitaires? Parfois? Toujours?

Merci.

Edit-add: Je voudrais ajouter un exemple comme une expérience bien:

class Foo { 
    public Foo() { .. } 
    private DateTime Now { 
     get { 
#if UNITTEST_Foo 
     return Stub_DateTime.Now; 
#else 
     return DateTime.Now; 
#endif 
     } 
    } 
    // .. rest of Foo members 
} 

comparant à

interface IDateTimeStrategy { 
    DateTime Now { get; } 
} 
class ProductionDateTimeStrategy : IDateTimeStrategy { 
    public DateTime Now { get { return DateTime.Now; } } 
} 
class Foo { 
    public Foo() : Foo(new ProductionDateTimeStrategy()) {} 
    public Foo(IDateTimeStrategy s) { datetimeStrategy = s; .. } 
    private IDateTime_Strategy datetimeStrategy; 
    private DateTime Now { get { return datetimeStrategy.Now; } } 
} 

qui permet la dépendance sortante sur "DateTime.Now" être écrasé par une interface C#. Cependant, nous avons maintenant ajouté un appel de dispatch dynamique où static suffirait, l'objet est plus grand même dans la version de production, et nous avons ajouté un nouveau chemin d'échec pour le constructeur de Foo (allocation peut échouer).

Est-ce que je ne m'inquiète de rien ici? Merci pour les commentaires jusqu'à présent!

Répondre

3

Essayez de garder le code de production distinct du code de test. Maintenir différentes hiérarchies de dossiers .. différentes solutions/projets.

Sauf si .. vous êtes dans le monde de l'ancien code C++. Ici tout va ... si des blocs conditionnels vous aident à tester une partie du code et vous voyez un avantage ... Par tous les moyens, faites-le. Mais essayez de ne pas le laisser devenir plus désordonné que l'état initial. Clairement commenter et délimiter les blocs conditionnels. Procéder avec prudence. C'est une technique valide pour obtenir le code existant sous un harnais de test.

+0

Voulez-vous dire "ceci est acceptable pour les bases de code existantes lors de l'ajout incrémentiel de tests unitaires" ou "cela fonctionne en C++, mais devrait être découragé lors du démarrage d'un nouveau projet C++"? – Aaron

+0

Première clause dans votre séquence OR. C'est une bonne technique pour tester le code existant sans trop perturber le code (vous n'êtes pas sûr de faire ces changements car vous n'avez pas le filet de sécurité des tests). – Gishu

+0

Merci, ça a plus de sens. – Aaron

2

Je pense que cela réduit la clarté pour les personnes qui examinent le code. Vous ne devriez pas avoir à vous souvenir qu'il y a une étiquette conditionnelle autour du code spécifique pour comprendre le contexte.

1

Non c'est terrible. Il fuit test dans votre code de production (même si elle est désactivée)

Mauvais mauvais.

+0

Il est facile de dire "non, c'est horrible, ne le faites pas". Que devrais-je faire à la place? – Aaron

0

Il peut être utile en tant qu'outil sur lequel s'appuyer pour la testabilité dans une grande base de code. Je peux voir comment vous pourriez utiliser ces techniques pour permettre des changements plus petits et éviter un refactoring "big bang". Cependant, je m'inquiéterais de trop m'appuyer sur une telle technique et j'essaierais de faire en sorte que de telles astuces ne vivent pas trop longtemps dans le code, sinon vous risquez de rendre le code d'application très complexe et difficile à suivre.

1

Le code de test doit être évident et ne pas être mélangé dans les mêmes blocs que le code testé.

C'est à peu près la même raison que vous ne devriez pas écrire

if (globals.isTest) 
1

Je pensais que d'une autre raison pour laquelle c'était terrible:

Plusieurs fois, vous quelque chose moquez/stub, vous voulez ses méthodes afin d'obtenir différents résultats en fonction de ce que vous testez. Cela empêche cela ou le rend gênant comme tout.

+0

En quoi est-ce plus compliqué que d'utiliser une interface C#? Dans les deux cas, vous disposez d'un corps d'implémentation de méthode pour la simulation et d'un corps d'implémentation de méthode pour le comportement de production. – Aaron

+0

Avez-vous utilisé un cadre moqueur? Vous n'avez pas d'autres corps à tester. De plus, je parle de situations où vous voulez, disons, 7 comportements différents selon votre contexte. C'est juste une idée horrible. Ne fais pas ça. –

Questions connexes