Les tests unitaires méthodes d'usine qui ont une classe concrète comme un type de retour

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

  •  21-08-2019
  •  | 
  •  

Question

J'ai donc une classe d'usine et je suis en train de travailler à ce que les tests unitaires devraient faire. De cette question je pouvais vérifier que le interface renvoyée est d'un type particulier de béton que j'attendre.

Que dois-je vérifier si l'usine est de retour types de béton (car il n'y a pas besoin - en ce moment - à utiliser pour les interfaces)? Actuellement, je fais quelque chose comme ce qui suit:

[Test]
public void CreateSomeClassWithDependencies()
{
    // m_factory is instantiated in the SetUp method
    var someClass = m_factory.CreateSomeClassWithDependencies();

    Assert.IsNotNull(someClass);
}

Le problème est que le semble un peu redondant Assert.IsNotNull.

En outre, ma méthode d'usine pourrait être mise en place des dépendances de cette classe particulière comme ceci:

public SomeClass CreateSomeClassWithDependencies()
{
    return new SomeClass(CreateADependency(), CreateAnotherDependency(),
                         CreateAThirdDependency());
}

Et je veux vous assurer que ma méthode d'usine met en place toutes ces dépendances correctement. Yat-il pas d'autre façon de le faire alors pour rendre ces dépendances propriétés que je puis public/internal vérifier dans le test unitaire? (Je ne suis pas un grand fan de modifier les sujets de test en fonction de l'essai)

Edit: En réponse à la question de Robert Harvey, j'utilise NUnit comme mon cadre de tests unitaires (mais je ne l'aurais pas pensé que cela ferait trop de différence)

Était-ce utile?

La solution

Souvent, il n'y a rien de mal à créer des propriétés publiques qui peuvent être utilisés pour le test basé sur l'état. Oui: Il est code créé pour permettre un scénario de test, mais ça fait mal votre API? Est-il concevable que d'autres clients trouveraient la même propriété utile plus tard?

Il y a une ligne fine entre le code spécifique à l'essai et de conception-piloté par les tests. Nous ne devons pas introduire un code qui n'a pas d'autre possibilité que de satisfaire à une exigence de test, mais il est tout à fait correct d'introduire un nouveau code qui suivent les principes de conception généralement acceptée. Nous laissons les tests lecteur notre conception - c'est pourquoi nous appelons TDD:)

Ajout d'une ou plusieurs propriétés à une classe pour donner à l'utilisateur une meilleure possibilité d'inspecter cette classe est, à mon avis, souvent une chose raisonnable à faire, donc je ne pense pas que vous devriez rejeter l'introduction de telles propriétés.

En dehors de cela, je seconde la réponse de Nader:)

Autres conseils

Si l'usine est de retour types de béton, et vous garantit que votre usine retourne toujours un type de béton, et non nul, alors non, il n'y a pas aussi beaucoup de valeur dans le test. Il ne vous permet de vous assurer, au fil du temps que cette attente ne soit pas violé, et des choses comme des exceptions ne sont pas jetés.

Ce style de test permet simplement sûr que, comme vous apportez des modifications à l'avenir, votre comportement d'usine ne changera pas sans que vous le sachiez.

Si votre langue prend en charge, pour vos dépendances, vous pouvez utiliser la réflexion. Ce n'est pas toujours le plus facile à entretenir, et les couples vos essais très étroitement à votre mise en œuvre. Vous devez décider si cela est acceptable. Cette approche a tendance à être très fragile.

Mais vous semblez vraiment essayer de séparer les classes sont construites, de la façon dont les constructeurs sont appelés. Vous pourriez être mieux avec l'aide d'un cadre de DI pour obtenir ce genre de flexibilité.

Par new - ing tous vos types que vous avez besoin, vous ne vous donnez pas beaucoup de coutures (une couture est un endroit où vous pouvez modifier le comportement de votre programme sans modifier en ce lieu) pour travailler avec.

Avec l'exemple que vous donnez bien, vous pourriez tirer une classe de l'usine. Ensuite override / CreateADependency() maquette, et CreateAnotherDependency() CreateAThirdDependency(). Maintenant, lorsque vous appelez CreateSomeClassWithDependencies(), vous êtes en mesure de sens si oui ou non les dépendances correctes ont été créées.

Remarque: la définition de "couture" vient du livre de Michael Feather, "Travailler efficacement avec Legacy Code". Il contient des exemples de nombreuses techniques pour ajouter testabilité à code non testé. Vous trouverez peut-être très utile.

Ce que nous faisons est de créer les usines avec dépendances, et nous utilisons un cadre d'injection de dépendance pour remplacer les usines simulées pour les vrais lorsque le test est exécuté. Ensuite, nous avons mis en place les attentes appropriées sur ces usines simulacres.

Vous pouvez toujours vérifier des choses avec la réflexion. Il n'y a pas besoin d'exposer quelque chose juste pour les tests unitaires. Je trouve assez rare que je dois atteindre avec la réflexion et peut-être un signe d'une mauvaise conception.

En regardant votre exemple de code, oui la Assertion ne semble pas nulle redondante, en fonction de la façon dont vous conçu votre usine, certains objets nuls retour de l'usine par opposition à exceptioning sur.

Si je comprends bien, vous voulez vérifier que les dépendances sont correctement construites et transmises à la nouvelle instance?

Si je ne pouvais pas utiliser un cadre comme Google Guice, je ne serais probablement le faire quelque chose comme ça (ici en utilisant JMock et Hamcrest):

@Test
public void CreateSomeClassWithDependencies()
{
    dependencyFactory = context.mock(DependencyFactory.class);
    classAFactory = context.mock(ClassAFactory.class);

    myDependency0 = context.mock(MyDependency0.class);
    myDependency1 = context.mock(MyDependency1.class);
    myDependency2 = context.mock(MyDependency2.class);
    myClassA = context.mock(ClassA.class);

    context.checking(new Expectations(){{
       oneOf(dependencyFactory).createDependency0(); will(returnValue(myDependency0));
       oneOf(dependencyFactory).createDependency1(); will(returnValue(myDependency1));
       oneOf(dependencyFactory).createDependency2(); will(returnValue(myDependency2));

       oneOf(classAFactory).createClassA(myDependency0, myDependency1, myDependency2);
       will(returnValue(myClassA));
    }});

    builder = new ClassABuilder(dependencyFactory, classAFactory);

    assertThat(builder.make(), equalTo(myClassA));
}

(si vous ne pouvez pas se moquer ClassA vous pouvez assigner une version non simulée à l'aide myClassA nouveau)

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