2

Nous avons récemment adopté les modèles de spécification pour la validation des objets de domaine et souhaitons maintenant introduire le test unitaire de nos objets de domaine pour améliorer la qualité du code.Spécification des tests unitaires de modèle

Un problème que j'ai trouvé est de savoir comment tester au mieux la fonctionnalité de validation montrée dans l'exemple ci-dessous. La spécification frappe la base de données, donc je veux pouvoir la simuler mais comme elle est instanciée en ligne, je ne peux pas le faire. Je pourrais travailler sur des interfaces mais cela augmente la complexité du code et comme nous avons beaucoup de spécifications, nous aurons finalement beaucoup d'interfaces (rappelez-vous que nous introduisons des tests unitaires et que nous ne voulons pas donner d'excuse à quelqu'un vers le bas). Étant donné ce scénario, comment pourrions-nous résoudre au mieux le problème de l'unité de test du modèle de spécification dans nos objets de domaine?

... 
public void Validate() 
{ 
    if(DuplicateUsername()) 
    { throw new ValidationException(); } 
} 

public bool DuplicateUsername() 
{ 
    var spec = new DuplicateUsernameSpecification(); 
    return spec.IsSatisfiedBy(this); 
} 

Répondre

5

Une introduction plus douce de Les coutures dans l'application ont pu être obtenues en faisant des méthodes de base virtual. Cela signifie que vous pouvez utiliser la technique Extraire et remplacer pour les tests unitaires. Dans le développement greenfield je trouve cette technique sous-optimale parce qu'il y a de meilleures alternatives disponibles, mais c'est un bon moyen de retrofit la testabilité au code déjà existant. Par exemple, vous écrivez que votre spécification frappe la base de données. Dans cette implémentation, vous pouvez extraire cette partie de la spécification à Factory Method que vous pouvez ensuite remplacer dans vos tests unitaires.

En général, le livre Working Effectively with Legacy Code fournit des conseils précieux sur la façon de rendre le code testable.

+0

Merci pour les commentaires Mark, je suis d'accord avec tout ce que vous dites mais espérais une solution décente à cela. Il y a quelque chose qui ne va pas bien dans l'héritage des cours et des méthodes principales dans le projet de test, je pense que ce serait les frais généraux que nous pourrions éviter si nous avions un design décent en premier lieu, ce que j'espère sortir de ce post. – Burt

+1

@Burt: J'ai peut-être mal compris votre question alors. La conception «décente» tourne autour de SOLID. En particulier, le principe ouvert/fermé est très important pour la testabilité. Cela implique à nouveau DI, ce qui signifie beaucoup d'interfaces et d'usines abstraites, et j'ai lu votre question à l'effet que vous ne pouviez pas vraiment vous permettre cette taxe maintenant. –

+0

Je ne voulais pas trop rocker le bateau mais ça ressemble à des interfaces qui seront le meilleur moyen de réaliser ce que je veux. – Burt

1

Vous pouvez extraire getDuplicateUsernameSpecification() dans une méthode publique propre, puis sous-classe et passer outre que pour vos tests.

+0

C'est une bonne idée, nous avons pensé à surcharger l'objet domaine et à surcharger la méthode DuplicateUsername mais ça ne marche pas bien avec moi. – Burt

1

Si vous utilisez IoC alors vous pouvez résoudre le DuplicateUsernameSpecification et dans le test Mockup le dernier

Edit: L'idée est de remplacer l'appel constructeur direct avec méthode usine. Quelque chose comme ceci:

public bool DuplicateUsername() 
{ 
    var spec = MyIocContainer.Resolve<DuplicateUsernameSpecification>(); 
    return spec.IsSatisfiedBy(this); 
} 
+1

L'utilisation d'un conteneur IoC en tant que localisateur de service n'est généralement pas considérée comme une meilleure pratique. Il vaut mieux utiliser l'injection de constructeur. Vous pouvez toujours utiliser un conteneur, mais cela n'a besoin que d'apparaître dans (ou d'être couplé) à un endroit de votre application. – TrueWill

+0

J'ai réfléchi à cela et j'ai essayé de l'implémenter, puis-je simuler une classe concrète sans interface en utilisant des frameworks moqueurs, c'est-à-dire MOQ? – Burt

+1

Je pense qu'il ne sera pas possible de se moquer d'une méthode qui n'est pas virtuelle, donc si une généralisation pourrait être possible pour la validation avec une interface comme ISpecification {bool IsSatisfiedBy (T target); } ça pourrait marcher. –

2

Si vous ne voulez pas faire l'injection de constructeur d'une usine, et faire les spécifications mockable ... Avez-vous pensé Typemock? C'est très puissant pour faire face à ce genre de chose. Vous pouvez lui dire de se moquer de l'objet suivant de type X qui doit être créé, et il peut se moquer de n'importe quoi, aucun virtual, etc. requis.