web-dev-qa-db-fra.com

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

Dans mon travail, nous utilisons Moq pour se moquer et Unity pour un conteneur IOC. Je suis assez nouveau dans ce domaine et je n'ai pas beaucoup de ressources au travail pour m'aider à déterminer les meilleures pratiques que je devrais utilisation.

À l'heure actuelle, j'ai un groupe d'interfaces de référentiel (Ex: IRepository1, IRepository2 ... IRepository4) qu'un processus particulier doit utiliser pour faire son travail.

Dans le code réel, je peux déterminer tous les objets IRepository en utilisant le conteneur IOC et en utilisant la méthode RegisterType ().

J'essaie de trouver la meilleure façon de tester la méthode qui nécessite les 4 référentiels mentionnés.

Je pensais que je pouvais simplement enregistrer une nouvelle instance du conteneur Unity IOC et appeler RegisterInstance sur le conteneur pour chaque objet simulé transmettant la valeur Mock.Object pour chacun. J'essaie de faire ce processus d'enregistrement réutilisable donc je n'ai pas à refaire la même chose encore et encore avec chaque test unitaire à moins qu'un test unitaire ne nécessite des données spécifiques pour revenir du référentiel. C'est là que réside le problème ... quel est le meilleur pratique pour configurer les valeurs attendues sur un référentiel simulé? Il semble que si j'appelle simplement RegisterType sur le conteneur Unity, je perdrais une référence à l'objet Mock réel et ne serais pas en mesure de remplacer le comportement.

35
Rob Packwood

Les tests unitaires ne doivent pas utiliser du tout le conteneur. L'injection de dépendance (DI) se déroule en deux phases:

  1. Utilisez des modèles DI pour injecter des dépendances dans les consommateurs. Vous n'avez pas besoin d'un conteneur pour cela.
  2. Au niveau de l'application Composition Root , utilisez un conteneur DI (ou DI du pauvre) pour câbler tous les composants ensemble.

Comment ne pas utiliser du tout de conteneur DI pour les tests unitaires

Par exemple, considérons une classe qui utilise IRepository1. En utilisant le modèle Injection de constructeur , nous pouvons faire de la dépendance 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 le mot clé readonly combiné à la clause Guard garantit que le champ repository n'est pas nul si l'instance a été instanciée avec succès.

Vous n'avez pas besoin d'un conteneur pour créer une nouvelle instance de MyClass. Vous pouvez le faire directement à partir d'un test unitaire à l'aide de Moq ou d'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 Unity pour les tests unitaires

Cependant, si vous devez absolument utiliser Unity dans vos tests, vous pouvez créer le conteneur et utiliser la méthode RegisterInstance:

[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...
}
62
Mark Seemann