les tests unitaires & constructeur d'injection de dépendance
J'ai une question concernant la façon dont on allait faire à propos de la conception d'une application adaptée pour les tests unitaires.
Je suis en train de mettre en œuvre le programme de réorientation stratégique (Seul Principe de Responsabilité), et à partir de ce que j'ai compris cela implique la séparation la plupart des fonctionnalités séparées, des classes à garder le code plus organisé. Par exemple, j'ai ce scénario spécifique.
Une classe RecurringProfile
, qui possède une méthode .ActivateProfile()
. Ce que cette méthode n'est de marquer le statut activé, et la création de la prochaine (première) paiement récurrent pour la prochaine date d'échéance. Je vais séparer les fonctionnalités pour créer le prochain paiement récurrent dans une salle de classe, par exemple RecurringProfileNextPaymentCreator
. Mon instant l'idée est d'avoir cette classe prendre la 'RecurringProfile'
comme un paramètre de son constructeur:
RecurringProfileNextPaymentCreator(IRecurringProfile profile)
Cependant, je pense que cela pourrait être problématique pour les tests unitaires. Je voudrais créer un test unitaire qui teste les ActivateProfile
fonctionnalité. Cette méthode permettrait d'obtenir une instance d'un IRecurringProfileNextPaymentCreator
via l'injection de dépendance (Ninject), et l'appel à la méthode .CreateNextPayment
.
Mon idée de créer un test unitaire était de créer une maquette d'un IRecurringProfileNextPaymentCreator
, et une substitution que pour que je puisse vérifier que le .ActivateProfile()
en fait appelé la méthode. Cependant, en raison du paramètre du constructeur, ce ne serait pas apte comme un constructeur par défaut pour NInject. Avoir à créer un personnalisé NInject juste de fournisseur pour ce cas (où je peux avoir le nombre de ces classes de tous les plus de la solution) serait un peu exagéré.
Toutes les idées /les meilleures pratiques comment aller à ce sujet?
--
Ci-dessous est un exemple de code concernant l'exemple ci-dessus: (Veuillez noter que le code est écrit à la main, et n'est pas syntaxiquement correct à 100%)
public class RecurringProfile
{
public void ActivateProfile()
{
this.Status = Enums.ProfileStatus.Activated;
//now it should create the first recurring payment
IRecurringProfileNextPaymentCreator creator = NInject.Get<IRecurringProfileNextPaymentCreator>();
creator.CreateNextPayment(this); //this is what I'm having an issue about
}
}
Et un échantillon de test unitaire:
public void TestActivateProfile()
{
var mockPaymentCreator = new Mock<IRecurringProfileNextPaymentCreator>();
NInject.Bind<IRecurringProfileNextPaymentCreator>(mockPaymentCreator.Object);
RecurringProfile profile = new RecurringProfile();
profile.ActivateProfile();
Assert.That(profile.Status == Enums.ProfileStatus.Activated);
mockPayment.Verify(x => x.CreateNextPayment(), Times.Once());
}
Aller jusqu'à l'exemple de code, ma question est de savoir si c'est une bonne pratique pour passer au-dessus de la RecurringProfile en tant que paramètre à la creator.CreateNextPayment()
méthode, ou s'il est plus logique de faire en quelque sorte passer le RecurringProfile
à la DI-cadre, lors de l'obtention d'une instance d'un IRecurringProfileNextPaymentCreator
, considérant que le IRecurringProfileNextPaymentCreator
toujours agir sur un IRecurringProfile
pour créer le prochain paiement. Espérons que cela rend la question un peu plus clair.
- faire de cette une réponse, pas un commentaire
Vous devez vous connecter pour publier un commentaire.
Que vous n'avez pas montrer tout le code je suppose que vous voulez faire quelque chose comme ce
N'est pas simple, non?
Mise à jour
Ne pas abuser d'un conteneur d'injection de dépendances comme un ServiceLocator. Votre idée d'injecter le paiement créateur comme ctor paramètre est la bonne façon de faire. ServiceLocator est considéré comme un anti-modèle moderne de l'architecture de l'application. Quelque chose comme le code ci-dessous devrait fonctionner correctement.
Vous ne devriez pas être à l'aide de votre conteneur d'injection de dépendances(Ninject) au cours de ces unités-tests. Vous le feriez manuellement injecter le simulacre de l'objet lors de newing la classe sous test. Vérifiez l'appel a été fait sur la maquette.
IRecurringProfileNextPaymentCreator' with a constructor taking the
IRecurringProfile` et en quelque sorte de la passer, ou si la méthodeIRecurringProfileNextPaymentCreator.CreateNextPayment()
devrait prendre laIRecurringProfile
en tant que paramètre à la méthode.