2010-10-27 26 views
3

Est-il généralement admis que vous ne pouvez pas tester de code à moins que le code ne soit configuré pour être testé?Possible de créer un code de test unitaire qui n'était pas initialement conçu pour être testé, sans changer de code?

Un peu hypothétique de code:

public void QueueOrder(SalesOrder order) 
{ 
    if (order.Date < DateTime.Now-20) 
     throw new Exception("Order is too old to be processed"); 
    ... 
} 

Certains considéreraient refactorisation dans:

protected DateTime MinOrderAge; 
{ 
    return DateTime.Now-20; 
} 

public void QueueOrder(SalesOrder order) 
{ 
    if (order.Date < MinOrderAge) 
     throw new Exception("Order is too old to be processed"); 
    ... 
} 

Note: Vous pouvez trouver des solutions encore plus compliquées; impliquant une interface IClock et usine. Cela n'affecte pas ma question.

Le problème avec la modification du code ci-dessus est que le code a changé. Le code a changé sans que le client demande de le modifier. Et tout changement nécessite des réunions et des conférences téléphoniques. Et je suis au point où il est plus facile de ne rien tester.

Si je ne suis pas disposé/capable de faire des changements: est-ce que cela ne me rend pas capable d'effectuer des tests?

Remarque: Le pseudo-code ci-dessus peut ressembler à C#, mais c'est seulement pour qu'il soit lisible. La question est agnostique de la langue.

Remarque: L'extrait de code hypothétique, le problème, le besoin de refactorisation et le refactoring sont hypothétiques. Vous pouvez insérer votre propre échantillon de code hypothétique si vous prenez ombrage avec le mien.

Remarque: Le code hypothétique ci-dessus est hypothétique. Toute relation avec un code, vivant ou mort, est une pure coïncidence.

Remarque: Le code est hypothétique, mais les réponses ne le sont pas. La question n'est pas subjective: comme je crois qu'il y a une réponse.


Mise à jour: Le problème ici, bien sûr, est que je ne peux pas garantir que le changement dans l'exemple ci-dessus ne rien casser. Bien sûr, j'ai refacturé une pièce de code à une méthode distincte, et le code est logiquement identique.

Mais je ne peux pas garantir que l'ajout d'une nouvelle méthode protégée n'a pas déporté la table de méthode virtuelle de l'objet, et si cette classe est dans une DLL alors je viens d'introduire une violation d'accès.

+1

Vous pouvez tester n'importe quel code. Certaines classes sont plus difficiles à tester que d'autres. Par exemple, une classe de servlet est plus difficile à tester qu'un POJO car la classe de servlet dépend de plus d'infrastructure qu'un POJO. – DwB

Répondre

4

La réponse est oui, du code devra être modifié pour être testable.

Mais il y a probablement beaucoup de code qui peut être testé sans avoir à le changer.Je me concentrerais d'abord sur l'écriture de tests pour ce genre de choses, puis je rédigerais des tests pour le reste lorsque les autres exigences du client vous donneraient l'occasion de le refactoriser de manière testable.

+0

Malheureusement, le refactoring est l'endroit où nous commençons à avoir des problèmes. :( –

+1

@Ian - Si vous essayez d'expliquer le concept au client, et qu'il ne l'achète pas, il devra simplement faire face à une augmentation constante des coûts de maintenance et de demande de changement, et diminuer régulièrement stabilité et performance. –

1

Le code peut être écrit dès le début pour être testable. Si ce n'est pas écrit depuis le début avec testabilité à l'esprit, vous pouvez toujours le tester, vous pouvez juste rencontrer quelques difficultés.

Dans votre code hypothétique, vous pouvez tester le code d'origine en créant un SalesOrder avec une date éloignée dans le passé, ou vous pouvez simuler DateTime.Now. Avoir le code refactorisé comme vous l'avez montré est plus agréable à tester, mais ce n'est pas absolument nécessaire.

0

Ceci est facile à réaliser dans certaines langues dynamiques. Par exemple je peux accrocher à l'intérieur des instructions import/using et remplacer une dépendance réelle par une dépendance, même si le SUT (System Under Test) l'utilise comme une dépendance implicite. Ou je peux redéfinir ces symboles (classes, méthodes, fonctions, etc.). Je ne dis pas que c'est la voie à suivre. Les choses devraient être refactorisées, mais il est plus facile d'écrire quelques tests de caractérisation.

1

Si votre code n'est pas conçu pour être testé, il est plus difficile de le tester. Dans votre exemple, vous devrez remplacer la méthode DateTime.Now qui n'est probablement pas une tâche facile.

Je pense que cela ajoute peu de valeur pour ajouter des tests à votre code ou le changement de code existant n'est pas autorisé alors vous ne devriez pas le faire. Cependant, si vous croyez en TDD, vous devriez écrire du nouveau code avec des tests.

0

Le problème avec ce genre de code est toujours, que cela crée et selon beaucoup de classes statiques, les types de cadres, etc etc ...

Une très bonne solution « injectent » fakes pour tous ces objets sont Typemock Isolator (qui est commercial, mais vaut chaque centime). Donc oui, vous pouvez tester le code existant, qui a été écrit sans testabilité à l'esprit. Je l'ai fait sur un gros projet avec Typemock et j'ai eu de très bons résultats.

Alternativement à Typemock, vous pouvez utiliser le framework MS Moles gratuit, qui est fondamentalement le même. C'est seulement qu'il a une API assez peu intuitive et qu'il est beaucoup plus difficile à apprendre et à utiliser.

HTH.
Thomas

1

Vous pouvez tester votre unité d'origine à l'aide d'une structure d'objet Mock. Dans ce cas, je moque l'objet SalesOrder à plusieurs reprises, en configurant une valeur Date différente à chaque fois, et test. Cela évite de modifier un code qui est expédié et vous permet de valider l'algorithme en question que la date de la commande n'est pas trop loin dans le passé.

Pour une meilleure vue d'ensemble de ce qui est possible étant donné les dépendances que vous avez affaire, et les fonctionnalités de langue que vous avez à votre disposition, je recommande Working Effective with Legacy Code.

0

Mockito + PowerMock pour Mockito.

Vous pourrez tester presque tout sans changer radicalement votre code. Mais certains setters seront nécessaires pour injecter les mocks.