2008-12-02 3 views
55

Cette question concerne les tests unitaires dans Visual Studio en utilisant MSTest (ceci est important, à cause de execution order de MSTest). La méthode marquée [TestInitialize] et le constructeur de la classe de test s'exécuteront avant chaque méthode de test. Donc, la question est: qu'est-ce que vous avez tendance à faire dans chacun de ces domaines? Evitez-vous d'effectuer certaines activités dans l'un ou l'autre? Quelle est ta raison: style, technique, superstition?Utilisez-vous TestInitialize ou le constructeur de classe de test pour préparer chaque test? et pourquoi?

Répondre

44

Le constructeur est juste une structure fournie par le langage. Chaque cadre de test semble avoir son propre cycle de vie contrôlé "initialiser". Vous aurez probablement des ennuis en utilisant le constructeur pour muter vos locaux.

MSTest: Vous obtenez une instance entière de la classe de test pour chaque TestMethod. Cela peut être le seul cas où il est possible de muter vos sections locales dans le constructeur, l'initialiseur ou la méthode de test sans affecter les autres méthodes de test.

public class TestsForWhatever 
{ 
    public TestsForWhatever() 
    { 
     // You get one of these per test method, yay! 
    } 

    [TestInitialize] 
    public void Initialize() 
    { 
     // and one of these too! 
    } 

    [TestMethod] 
    public void AssertItDoesSomething() { } 

    [TestMethod] 
    public void AssertItDoesSomethingElse() { } 
} 

MSpec: Vous obtenez seulement un Establish et Because pour toutes vos affirmations (It). Donc, ne mutez pas vos locaux dans vos affirmations. Et ne dépendez pas des mutations des locaux dans les contextes de base (si vous les utilisez).

[Subject(typeof(Whatever))] 
public class When_doing_whatever 
{ 
    Establish context =() => 
    { 
     // one of these for all your Its 
    }; 

    Because of =() => _subject.DoWhatever(); 

    It should_do_something; 
    It should_do_something_else; 
} 
+0

J'ai eu le même problème et vous venez de fournir la bonne explication, merci! – Raffaeu

+4

Vous pouvez également indiquer que '[ClassInitialize]' n'est exécuté qu'une seule fois par test (avant tout), il peut donc être utilisé pour toutes les routines d'installation coûteuses. – kmote

+4

-1: Vous ne devriez pas détester votre question; cela a beaucoup de sens, en fait. Voir, par exemple, [xUnit.net] (https://github.com/xunit/xunit): il est recommandé d'utiliser le constructeur comme * l'initialiseur de test *. Être «juste une structure fournie par la langue» n'est pas une mince affaire; quiconque écrit un cadre quelconque (frameworks de test inclus) ne doit pas * essayer * de réinventer la roue, et utiliser plutôt des standards bien définis (comme, vous le savez, utiliser des constructeurs pour initialiser des choses, et ainsi de suite). – rsenna

1

L'objet que vous testez n'a pas besoin d'être instancié dans la méthode [TestInitialize]. Vous pouvez tester le constructeur de votre objet dans une méthode de test [Test]. L'objet dans [TestInitialize] peut être pour configurer votre stockage de persistance ou pour préparer la valeur que l'objet testé utilisera dans les tests.

+2

Je sais cela. Vous pouvez instancier l'objet en ligne avec la déclaration si possible. Ma question est ce que vous faites dans l'un ou l'autre de ces endroits. Et pourquoi? –

+1

J'ai répondu à cette question dans ma réponse ... relire. –

+6

Vous n'avez pas répondu à cette question dans votre réponse. Lisez la question à nouveau. – Slauma

4

Je préfère utiliser la méthode [TestInitialize] pour effectuer l'instanciation de l'objet testé et de ses paramètres. Je n'effectue du travail dans le constructeur que s'il est nécessaire d'instancier une classe de base de test (qui est généralement l'endroit où je crée ou réactualise des dépôts, etc.). Cela m'aide à garder le code du framework de test et le code de test séparés logiquement et physiquement.

14

Le principal avantage d'utiliser soit TestInitialize() ou ClassInitialize() plutôt que l'instance de classe de test ou constructeurs statiques est sa nature explicite. Il indique clairement que vous faites une configuration avant vos tests. Faire cela régulièrement devrait améliorer la maintenabilité à long terme.

+2

Je ne suis pas d'accord. Qu'est-ce qui pourrait être plus clair qu'un constructeur? Bien sûr, vous devez savoir que vous obtenez une nouvelle instance de classe de test pour chaque test, mais c'est quelque chose que vous devriez vraiment savoir de toute façon. Et ce n'est pas comme 'TestInitialize' est un nom si évident qui ne peut pas causer de confusion: https://stackoverflow.com/questions/22999816/testinitialize-vs-classinitialize. –

15

Voici quelques avantages que j'ai trouvés avec TestInitialize.

  • Certaines variables d'environnement (par exemple TestContext) ne sont accessibles qu'après l'instanciation de la classe de test.
  • Peut nécessiter une implémentation avec une classe dérivée en marquant un résumé de méthode TestInitialize de base.
  • peut facilement remplacer une méthode de TestInitialize de base et déterminer si appeler les bases impl avant que les impl dérivés, après, ou pas du tout. En revanche, si vous dérivez une classe de test à partir d'une classe de test de base, dans le cas d'un constructeur sans paramètre, le cteur de base sera appelé si vous l'avez voulu ou non.
  • Sa définition explicite rend les intentions claires et complète la méthode TestCleanup. Vous pourriez argumenter que vous pouvez créer un destructor pour chaque constructeur, mais il n'est pas garanti que MS Test gérera les destructeurs comme vous vous en doutez.
+1

J'ai trouvé que MSTest * exécute une méthode 'public void Dispose' après chaque exécution de test. Il doit être public, et peu importe que vous implémentiez 'IDisposable': vous ne pouvez pas explicitement implémenter l'interface. – Sebazzz

0

Cela dépend du scénario. Si vous avez une classe de test, et pour une raison étrange si vous avez besoin de créer une instance sur une autre classe de test, vous devrez utiliser le constructeur.

Sinon essai initialize plus unique dans le concept. Tout d'abord, pour les mêmes raisons que ci-dessus, la seconde MS peut introduire plus de fonctionnalités sur cet attribut et vous en bénéficierez, avec le constructeur vous y serez coincé.

1

Je dis utiliser le constructeur à moins que vous avez besoin TestContext.

  1. Si vous pouvez garder les choses simples, pourquoi pas. Un constructeur est plus simple qu'un attribut magique.
  2. Vous pouvez utiliser readonly qui est une grande chose dans l'initialisation de test où vous voulez préparer des choses pour les tests qu'ils ne sont pas censés changer (idéalement les choses que vous préparez serait trop immuable).
+1

+1 pour la lecture seule. J'ai juste supprimé ma question à ce sujet quand j'ai vu ta réponse. Mais je pense d'habitude dans l'autre sens: j'utilise TestInitialize à moins que je ne veuille un attribut readonly, car il semble un meilleur ajustement de "langue" dans le contexte de test. Mais c'est juste une décision de conception. Je suis d'accord avec les deux approches. – heringer

Questions connexes