35 votes

Façon appropriée de simuler les objets du référentiel pour les tests unitaires à l'aide de Moq et Unity

À mon travail, nous sommes en utilisant Moq de se moquer et de l'Unité pour un conteneur IOC. Je suis assez nouveau à cela et n'ont pas beaucoup de ressources au travail pour m'aider à déterminer les meilleures pratiques à utiliser.

Maintenant, j'ai un groupe référentiel des interfaces (Ex: IRepository1, IRepository2... IRepository4) qu'un processus doit utiliser pour faire son travail.

Dans le code que j'ai peut déterminer toutes les IRepository objets en utilisant le conteneur IOC et à l'aide de la RegisterType() la méthode.

Je suis à essayer de comprendre la meilleure façon d'être en mesure de tester la méthode qui a besoin de 4 dépôts.

Je pensais que je pouvais tout simplement enregistrer une nouvelle instance de l'Unité conteneur IOC et appel RegisterInstance sur le conteneur pour chaque objet fantaisie en passant dans le Simulacre.La valeur de l'objet pour chacun d'eux. Je suis en train de faire de cette inscription, réutilisable, donc je n'ai pas de continuer à faire la même chose encore et encore, chaque unité de test, à moins qu'une unité de test nécessite certaines données spécifiques à revenir à partir du référentiel. C'est là que se trouve le problème... quelle est la meilleure pratique pour l'établissement de valeurs attendues sur un moqué de référentiel? Il semble comme si je viens de l'appeler RegisterType sur l'Unité de conteneur que je perdrais une référence à l'objet Fantaisie et ne serait pas en mesure de remplacer le comportement.

61voto

Mark Seemann Points 102767

Les tests unitaires ne doivent pas utiliser le conteneur à tous. L'Injection de dépendance (DI) est disponible en deux phases:

  1. Utilisez DI modèles d'injecter des dépendances dans les consommateurs. Vous n'avez pas besoin d'un conteneur pour le faire.
  2. Lors de l'application de la Composition de la Racine, l'utilisation d'un Conteneur d'injection de dépendances (ou du Pauvre DI), à fil de tous les éléments ensemble.

Comment ne pas les utiliser tout Conteneur d'injection de dépendances à tous pour les tests unitaires

Considérez, par exemple, une classe qui utilise IRepository1. En utilisant le Constructeur de l'Injection de modèle, nous pouvons faire de la dépendance d'un invariant de la classe.

public class SomeClass
{
    private readonly IRepository1 repository;

    public SomeClass(IRepository1 repository)
    {
        if (repository == null)
        {
            throw new ArgumentNullException("repository");
        }

        this.repository = repository;
    }

    // More members...
}

Notez que l' readonly mot-clé combinée avec la Garde Clause garantit que l' repository champ n'est pas nul si l'instance a été correctement instancié.

Vous n'avez pas besoin d'un conteneur pour créer une nouvelle instance de Maclasse. Vous pouvez le faire directement à partir d'une unité de test à l'aide de Moq ou un autre Test Double:

[TestMethod]
public void Test6()
{
    var repStub = new Mock<IRepository1>();
    var sut = new SomeClass(repStub.Object);
    // The rest of the test...
}

Voir ici pour plus d'informations...

Comment utiliser l'Unité pour les tests unitaires

Toutefois, si vous devez absolument utiliser l'Unité dans vos tests, vous pouvez créer le conteneur et l'utilisation de la RegisterInstance méthode:

[TestMethod]
public void Test7()
{
    var repMock = new Mock<IRepository1>();

    var container = new UnityContainer();
    container.RegisterInstance<IRepository1>(repMock.Object);

    var sut = container.Resolve<SomeClass>();
    // The rest of the test...
}

5voto

jfar Points 19380

Vous ne vous moqueriez pas de vos référentiels, vous créeriez plutôt des talons avec des types codés en dur comme valeurs de retour. Ensuite, vous créez deux configurations Unity, une pour vivre où vous chargez dans les types de béton de production et une autre pour tester où vous chargez dans vos talons en mémoire.

De cette façon, vous bénéficiez également d'un "mode de test" où vous pouvez exécuter votre application sur un magasin de données connu en mémoire.

 public DogRepository : IDogRepository
{
    List<Dog> _doggies = new List<Dog>() 
                              {
                                  new Dog("Spot", "Labrador"),
                                  new Dog("Happy", "Werewolf")
                              };

   public GetDogByName( string dogName )
   {
       return _doggies.Where( @d => @d.Name == dogName );
   }

}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X