Comment puis-je tester par un test une méthode qui s'attend à la mise à jour d'un objet via une référence?

StackOverflow https://stackoverflow.com/questions/1424854

  •  07-07-2019
  •  | 
  •  

Question

Je ne parviens pas à tester une méthode qui modifie certaines propriétés d'un type de référence qui lui est transmise.

Par exemple, supposons que j'ai une classe appelée Policy.

Policy policy = new Policy();
policy.Status = Active;

Je passe ensuite cette politique au gestionnaire de politiques afin de l'inactiver.

policyManager.InactivatePolicy(policy);

La méthode de stratégie inactivée effectue les opérations suivantes:

public void InactivatePolicy(Policy policy)
{
    policy.Status = Inactive;
    UpdatePolicy(policy); //saves the updated policy details via nhibernate
}

Ce qui me pose problème, c’est le test unitaire de cette méthode DoSomething. (ignorez le fait que ce qu'il fait dans cet exemple est inutile)

public void DoSomething(Policy policy)
{
    Policy policy = new Policy();
    policy.Status = Active;

    policyManager.InactivatePolicy(policy);
}

Comme je mock out Policy Manager, l'état n'est pas défini sur inactif. et par conséquent, quand j'affirme qu'après DoSomething, on appelle l'état de la la stratégie est inactive. Je reçois un échec de test car il est toujours actif.

[Test]
public void TheStatusShouldBeInactiveWhenWeDoSomething()
{
    Mock<IPolicyManager> policyManagerMock = new Mock<PolicyManager>();
    MyClass mc = new MyClass(policyManagerMock.Object);

    Policy policy = new Policy();
    policy.Status = Active;

    mc.DoSomething(policy);

    Assert.That(policy.Status, Is.EqualTo(Inactive)); //this fails      
}

Je suis donc dans une situation où le code fonctionne dans la réalité, mais pas dans les tests unitaires.

La seule façon pour moi de résoudre ce problème consiste à faire en sorte que la méthode InactivatePolicy du gestionnaire de règles renvoie le code modifié. politique afin que je puisse me moquer de la valeur de retour attendu.

public Policy InactivatePolicy(Policy policy)
{
    policy.Status = Inactive;
    UpdatePolicy(policy); //saves the updated policy details via nhibernate
    return policy;
}

[Test]
public void TheStatusShouldBeInactiveWhenWeDoSomething()
{
    Mock<IPolicyManager> policyManagerMock = new Mock<PolicyManager>();
    MyClass mc = new MyClass(policyManagerMock.Object);

    Policy expectedInactivePolicy = new Policy();
    expectedInactivePolicy.Status = Inactive;

    Policy policy = new Policy();
    policy.Status = Active;

    policyManagerMock
        .Setup(p => p.InactivatePolicy(policy))
        .Returns(expectedInactivePolicy);   

    mc.DoSomething(policy);

    Assert.That(policy.Status, Is.EqualTo(Inactive)); //this now succeeds

}

Généralement, lorsque je lutte pour effectuer des tests unitaires, c'est une indication que je fais les choses mal.

Quelqu'un sait-il s'il existe un meilleur moyen de le faire? Sommes-nous essentiellement obligés de renvoyer des valeurs qui devaient initialement être mises à jour via la valeur de référence transmise à la méthode?

Mon problème est-il que le gestionnaire de règles ne devrait pas avoir de méthode InactivatePolicy mais qu'elle devrait plutôt se trouver sur l'objet Policy lui-même et que la mise à jour de la base de données a été appelée plus tard?

Était-ce utile?

La solution

Vous ne devriez pas vous moquer du PolicyManager, vous devriez vous moquer de la méthode UpdatePolicy car vous souhaitez toujours tester les fonctionnalités de la méthode DoSomething.

De plus, vous testez probablement trop haut dans l'arbre.

Vous devez tester la méthode InactivatePolicy () de manière isolée et vérifier que seule la fonctionnalité fonctionne, puis tester la méthode DoSomething (), à nouveau dans Isolation.

Vous avez 2 unités de code distinctes ici et vous devriez avoir des tests unitaires qui testent spécifiquement chaque unité.

Autres conseils

Randonnée

Je ne vous suis pas très bien.

Si vous ne testez pas le fait qu'il soit configuré sur true via NHibernate (c'est-à-dire que vous allez supposer que cela fonctionne), que testez-vous même? Pourquoi avoir la peine de tester, du tout, que la valeur est définie, étant donné que dans le code de production, vous supposerez qu'il en est ainsi? Même si vous deviez simuler de manière triviale un système qui le définit comme vrai, je ne vois pas l'intérêt, car ce n'est pas la même chose que le code de production.

Au mieux, j’envisagerais d’avoir un magasin de données «moqueur»; pas nHibernate, ça ne fait rien. Dans ce cas, il serait implémenté dans la classe UpdatePolicy , avec un "MockRepo" au lieu de "nHibernateRepo".

De cette manière, si vous configurez le repo de manière appropriée, vous pouvez le voir être défini.

Bien que je puisse me demander l’intérêt de cela, parce que votre code nHibernate a peut-être un bogue et que tout ce que vous vérifiez, c’est le réglage d’un booléen.

Résumé

Pourquoi ne pas simplement avoir une base de test dev sur laquelle vous pouvez exécuter ce test?

Je pense que le test est incorrect car vous testez en réalité l'objet fictif et son impact sur l'état actif de votre objet de stratégie au lieu de tester votre objet d'origine et même si le test réussit dans un scénario réel, PolicyManager peut se comporter différemment et provoquer un comportement erroné. échouer. Vous feriez peut-être mieux de tester PolicyManager et sa méthode UpdateInactive dans un test unitaire et test d'intégrité pour tester DoSomething avec le vrai PolicyManager.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top