Question

J'essaie d'apprendre l'injection de dépendances et j'ai rencontré un problème lors des tests unitaires de l'application.

J'écris une application console et le conteneur est créé et initialisé dans Main(), il est disponible sous forme de get-property dans Program.Container, donc n'importe où dans ma candidature, je peux appeler Program.Container.Resolve<..>().

J'ai une classe ServiceValidator comme celle-ci :

public class ServiceValidator
{
    private readonly IConfiguration _configuration;
    private readonly IService _service;

    public ServiceValidator(IConfiguration configuration, IService service)
    {
        _configuration = configuration;
        _service = service;
    }

Dans une autre classe, j'utilise

ServiceValidator serviceValidator = Program.Container.Resolve<ServiceValidator>();
serviceValidator.VerifyVersion();

C'est l'appel à Program.Container.Resolve cela me pose des problèmes lors du test unitaire, car il n'a pas été configuré.

Est-ce une mauvaise pratique d'appeler solve sur le conteneur ?Je pourrais créer l'instance ServiceValidator dans Main() et transmettre l'objet, mais cela semble stupide car cela entraînerait de nombreux paramètres pour les objets qui viennent d'être transmis à la méthode suivante.

Je suppose donc qu'il est acceptable d'appeler Resolve au sein d'une classe, mais le conteneur doit ensuite être configuré pour le test unitaire.Comment dois-je procéder, dois-je déplacer le conteneur vers un autre endroit que la classe Program ?Que recommanderais-tu?

Si c'est important, j'utilise Unity et C#

Merci :-)

Était-ce utile?

La solution

  

Est-ce une mauvaise pratique, d'appeler résoudre sur le conteneur? Je pourrais créer l'instance ServiceValidator dans Main () et transmettre l'objet, mais cela semble stupide, car cela créerait de nombreux paramètres pour les objets qui viennent d'être transmis à la méthode suivante.

Lorsque vous utilisez l'injection de dépendance jusqu'au bout, vous n'avez pas besoin de transmettre beaucoup de paramètres aux objets. Le constructeur de chaque objet ne doit avoir comme paramètres que les dépendances qu’il utilise lui-même directement; il ne saura rien des dépendances transitives de ses dépendances directes.

Donc, si vous avez une classe X qui nécessite un ServiceValidator, alors la classe X aura un paramètre constructeur de type ServiceValidator. Ensuite, si une classe Y utilise la classe X, la classe Y aura un paramètre constructeur de type X. Notez que Y ne sait rien à propos de ServiceValidator. Vous n'avez donc pas besoin de passer ServiceValidator d'une classe à un autre - le seul endroit où il est utilisé est lors de la construction de X, et cela se fait souvent par un framework DI ou à un seul endroit dans une usine manuscrite.

Quelques liens pour plus d'informations:

Autres conseils

J'autorise généralement les appels pour résoudre les dépendances du conteneur dans des endroits comme main, même si j'essaie toujours de les réduire au minimum.Ce que je fais ensuite, c'est configurer le conteneur dans une méthode d'initialisation d'une classe de test.Je l'ai initialisé avec de fausses implémentations pour toute classe de test qui doit appeler le conteneur.

Les classes de test qui n'appellent rien nécessitant l'initialisation du conteneur peuvent alors l'ignorer et ne pas utiliser les faux.J'utilise habituellement des simulations dans ces cas-là.

J'utilise également le Localisateur de services Microsoft de sorte que la dépendance que je prends concerne quelque chose du .NET Framework plutôt que sur un conteneur spécifique.Cela me permet d'utiliser à l'avenir tout ce que je veux, même un contenant brassé maison.

Vous pouvez utiliser une classe statique en tant qu'initialiseur pour votre conteneur. Quelque chose comme BootStrapper.cs conviendrait. Vous pouvez ensuite référencer les méthodes de classe à la fois dans votre code et dans vos tests.

Eh bien, techniquement, vous faites un centre de service dans votre classe.

Je me souviens d'avoir lu cet article il y a quelque temps:

http://martinfowler.com/articles/injection.html

Pour mes cours, je n’essaye jamais d’utiliser Resolve en eux. Je crée les objets à travers le conteneur quand j'en ai besoin. Pour les tests unitaires, j'utilise soit des classes de bibliothèque fictive et de stub.

Le problème réside dans le fait que vous essayez de tester la méthode Main. Cette méthode est pratiquement impossible à effectuer des tests unitaires.

Je dirais qu'il est préférable de ne pas effectuer de test unitaire de votre méthode Main car:

  • L'accent mis sur les tests unitaires modernes concerne la conception
  • Vous devriez minimiser la dépendance à la configuration dans les tests unitaires. La configuration peut être testée avec des tests de fumée ou d’intégration.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top