2009-01-28 7 views
5

Ich bin ein großer Fan des xUnit.NET-Frameworks; Ich finde es leicht, einfach, sauber und erweiterbar.Erweitern Sie xUnit.NET, um benutzerdefinierten Code zu verwenden, wenn Sie eine Klasse bearbeiten und Testmethoden lokalisieren

Lassen Sie uns jetzt sagen, dass ich eine Klasse wie folgt:

public class AdditionSpecification 
{ 
    static int result; 

    public void Because() 
    { 
    result = 2 + 2; 
    } 

    public void Result_is_non_zero() 
    { 
    Assert.True(result <> 0); 
    } 

    public void Result_is_correct() 
    { 
    Assert.Equal(4, result); 
    } 
} 

Mit der Testklasse I oben xUnit.NET wollen 2 Testfälle zu sehen und die Da() -Methode vor jedem von ihnen zu laufen.

alle Probleme Abgesehen Sie mit meiner Klasse oder Methodennamen, die Struktur dieser Test/Spezifikation, die xUnit.NET Rahmen oder BDD, hier meine Frage haben:

Wie kann ich xUnit sagen. NET, die ich anpassen möchte, wie es identifiziert und führt Testmethoden aus dieser Klasse ohne mit einem benutzerdefinierten [Tatsache] -ähnlichen Attribut für jede Ziel-Testmethode?

Ich weiß, dass ich von BeforeAfterAttribute ableiten kann, um jede Testmethode mit benutzerdefinierten vor und nach der Ausführung zu dekorieren. Wie kann ich das auf Klassenebene tun? Muss ich einen benutzerdefinierten Läufer schreiben?

Antwort

9

So stellt sich heraus, dass ich nach der ITestClassCommand.EnumerateTestMethods() -Methode gesucht habe.

  1. Der Standard xUnit.NET Testläufer über alle Klassen in Ihre Testanordnung durchlaufen wird.
  2. Für jeden wird es nach einem RunWithAttribute suchen; das ist Ihre Chance, die ITestClassCommand Implementierung zu überschreiben, die verwendet wird, um Methoden zu identifizieren, die Tests enthalten. (RunWithNUnit ist ein gutes Beispiel)
  3. ITestClassCommand.EnumerateTestMethods() wird aufgerufen, um die Testklasse zu verarbeiten und eine IEnumerable der Testmethoden zurückzugeben.
  4. jeder Test IMethodInfo wird dann auf ITestClassCommand.EnumerateTestCommands (IMethodInfo testmethod) geleitet wird, die IEnumerable von ITestCommands
  5. jeder ITestCommand erhalten dann die Möglichkeit, ausgeführt und gegeben ein Ergebnis zurückzukehren.

    [RunWithMyTestClassCommand] 
    public class AdditionSpecification 
    { 
        static int result; 
    
        public void Because() 
        { 
        result = 2 + 2; 
        } 
    
        public void Result_is_non_zero() 
        { 
        Assert.True(result <> 0); 
        } 
    
        public void Result_is_correct() 
        { 
        Assert.Equal(4, result); 
        } 
    } 
    

    schließlich in MyTestClassCommand, erhalte ich: Ich konnte mein obiges Beispiel mit dekorieren

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 
    public class RunWithMyTestClassCommandAttribute : RunWithAttribute 
    { 
        public RunWithMyTestClassCommandAttribute() 
           : base(typeof(MyTestClassCommand)) {} 
    } 
    

    Dann:

Im Fall meines obigen Beispiels würde ich brauche so etwas wie zu Opportunity zwischen EnumerateTestMethods() und EnumerateTestCommands (IMethodInfo testMethod), um die Logik zu verwenden, die ich ITestCommand-Instanzen suchen und erstellen möchte, die als einzelne Tests ausgeführt werden.

BTW, bei der Untersuchung dieses Problems, stieß ich auf einen kleinen Fehler im xUnit.NET-Framework, wo eine benutzerdefinierte EnumerationTestMethods() durch EnumerateTestMethods() erzeugte IMethodInfo nie in EnumerateTestCommands (..) angezeigt wurde, da es ausgepackt wurde vom Testläufer oder einer seiner Fabriken neu verpackt.

I vorgelegt this issue zum xUnit Projekt auf Codeplex und es war corrected on May 30th 2009 für xUnit.NET 1.5 CTP 2

9

Mit der IUseFixture von xUnit.net können Sie jedes Gerät konfigurieren. Sie könnten daher Ihre eigene Befestigungs Klasse definieren:

public class AdditionFixture : IDisposable 
{ 
    public int Because() 
    { 
    return 2 + 2; 
    } 

    public void Dispose() 
    { 
    //test tear down code 
    }  
} 

Ihre Testklasse kann diese dann implementieren (mit setFixture erfordern Umsetzung):

public class AdditionSpecification : IUseFixture<AdditionFixture> 
{ 
    int result; 

    public void SetFixture(AdditionFixture Fixture) 
    { 
    result = Fixture.Because(); 
    } 

    [Fact] 
    public void Result_is_non_zero() 
    { 
    Assert.True(result <> 0); 
    } 

    [Fact] 
    public void Result_is_correct() 
    { 
    Assert.Equal(4, result); 
    } 
} 

Die xUnit Läufer eine einzelne Instanz Ihrer Leuchte schaffen wird, und übergeben Sie es vor dem Ausführen jedes Tests in SetFixture. Nachdem alle Tests durchgeführt wurden, entsorgt der Läufer das Gerät, wenn IDisposable implementiert wird. Ich hoffe das hilft!

Das xUnit-Wiki auf Codeplex enthält weitere Informationen, einschließlich eines guten Beispiels zur Implementierung von IUseFixture zur Verwaltung einer Datenbankverbindung für Ihre Testadapter.

+1

Danke für versucht zu helfen, aber diese Antwort keine Antwort auf die Frage, die ich gefragt; Wie kann ich xUnit.NET mitteilen, welche Methoden ich basierend auf einer Konvention ausführen möchte, ohne das [Fact] -Attribut zu verwenden? –

+0

Die von mir vorgeschlagene Lösung erzielt den Effekt, dass Because() ausgeführt wird, bevor jeder Test ausgeführt wird. Ich merke, dass ich immer noch das Attribut [Fakt] verwende, um dies zu erreichen. Darf ich fragen, warum Sie vermeiden wollen, [Fakten] s zu verwenden? – BenA

+0

Um einige Zeremonie aus dem Schreiben von Testvorrichtungen zu entfernen; Wenn ich eine Konvention zur Codierung meiner Testgeräte befolge, dann kann ich diese Logik in den Runner (oder in einen benutzerdefinierten ITestClassCommand und RunWithAttribute, wie es passiert) und alle [Fact] -Attribute, so dass meine Tests ein bisschen lesbarer und lesbarer werden schneller zu programmieren. –

Verwandte Themen