2012-05-08 8 views
8

Ich habe 2 Klassen:Wie Schreib Stubmethode mit NUnit in C#

  • FirstDeep.cs
  • SecondDeep.cs

    Ich habe einfachen Code zum Beispiel:

 

class FirstDeep 
    { 
     public FirstDeep() { } 

     public string AddA(string str) 
     { 
      SecondDeep sd = new SecondDeep(); 
      bool flag = sd.SomethingToDo(str); 

      if (flag == true) 
       str = string.Concat(str, "AAA"); 
      else 
       str = string.Concat(str, "BBB"); 

      return str; 
     } 
    } 
 

und

class SecondDeep 
    { 
     public bool SomethingToDo(string str) 
     { 
      bool flag = false; 
      if (str.Length < 10) 
      { 
       //todo something in DB, and after that flag should be TRUE 
      } 
      return flag; 
     } 
    } 

Dann möchte ich Unit-Test für die Methode „AddA“ schreiben:

class Tests 
    { 
     [Test] 
     public void AddATest() 
     { 
      string expected = "ABCAAA"; 

      FirstDeep fd = new FirstDeep(); 
      string res = fd.AddA("ABC"); 

      Assert.AreEqual(expected, res); 
     } 
    } 

Und danach habe ich Schwierigkeiten haben, ich weiß nicht, wie richtige Schreibstummel für Methode SomethingToDo in meinem Test-Klasse. Ich habe immer falsch. Ich sollte nur TRUE zurückgeben. Aber wie?

+0

Sie noch mit Ihrem Muster arbeiten können: introduce 'bool erwartet = false; SecondDeep sd = neu SecondDeep(); bool actualResult = sd.SomethingToDo ("ABC"); Assert.AreEqual (expected, actualResult); '...!? Wenn dies Ihre Bedürfnisse nicht berücksichtigt, sollten Sie überlegen, Ihre Frage zu erörtern und zu verbessern! –

+0

Haben Sie Ihren Code debugged? Wenn es in der Datenbank passiert, können wir Ihnen nicht helfen, da wir keine Details darüber haben, was dort passiert. – Jon

+0

Ja, ich debugged meinen Code, und wo ich schrieb: "// todo etwas in der DB, und nach diesem Flag sollte TRUE sein" Ich benutze Klasse MembershipUser von .NET und diese Methode kann nicht mit DB verbinden, deshalb sollte ich Gib in diesem Fall nur wahr zurück. – Smit

Antwort

9

Eine gute Möglichkeit, um Stubs zu schreiben, ist die Verwendung Abhängigkeitsinjektion. FirstDeep hängt von SecondDeep ab und in Ihrem Test möchten Sie SecondDeep durch einen Stub ersetzen.

zunächst Ihre vorhandenen Code ändern, indem eine Schnittstelle für SecondDeep extrahieren und dann injizieren, dass in FirstDeep im Konstruktor:

interface ISecondDeep { 

    Boolean SomethingToDo(String str); 

} 

class SecondDeep : ISecondDeep { ... } 

class FirstDeep { 

    readonly ISecondDeep secondDeep; 

    public FirstDeep(ISecondDeep secondDeep) { 
    this.secondDeep = secondDeep; 
    } 

    public String AddA(String str) { 
    var flag = this.secondDeep.SomethingToDo(str); 
    ... 
    } 

} 

Beachten Sie, dass FirstDeep nicht mehr schafft eine SecondDeep Instanz. Stattdessen wird eine Instanz in den Konstruktor eingefügt.

In Ihrem Test, den Sie einen Stub für ISecondDeep schaffen können, wo SomethingToDo immer true zurück:

class SecondDeepStub : ISecondDeep { 

    public Boolean SomethingToDo(String str) { 
    return true; 
    } 

} 

Im Test verwenden Sie die Stub:

var firstDeep = new FirstDeep(new SecondDeepStub()); 

In Produktionscode verwenden Sie den „real "SecondDeep:

Die Verwendung eines Dependency-Injection-Containers und eines Stubbing-Frameworks kann vieles einfacher machen.

Wenn Sie Ihren Code nicht umschreiben möchten, können Sie ein Framework zum Abfangen von Anrufen wie Microsoft Moles verwenden. In der nächsten Version von Visual Studio wird eine ähnliche Technologie in der Fakes Framework verfügbar sein.

4

Um Ihren Code testbar zu machen, instanziieren Sie keine Abhängigkeiten innerhalb Ihrer Klasse. Verwenden Sie dependency injection (über Konstruktor, Eigenschaft oder Parameter). Verwenden Sie auch abstrakte Klassen oder Schnittstellen spöttisch von Abhängigkeiten zu ermöglichen:

class FirstDeep 
{ 
    private ISecondDeep oa; 

    public FirstDeep(ISecondDeep oa) 
    { 
     this.oa = oa; 
    } 

    public string AddA(string str) 
    { 
     return String.Concat(str, oa.SomethingToDo(str) ? "AAA" : "BBB"); 
    } 
} 

Je nach Abstraktionen können Sie Ihre Klasse in Isolation testen.

interface ISecondDeep 
{ 
    bool SomethingToDo(string str); 
} 

class SecondDeep : ISecondDeep 
{ 
    public bool SomethingToDo(string str) 
    { 
     bool flag = false; 
     if (str.Length < 10) 
     { 
      // without abstraction your test will require database 
     } 
     return flag; 
    } 
} 

Hier ist Testprobe (mit Moq).Es zeigt Ihnen, wie Sie true von Anruf zu Ihrer verspottet Abhängigkeit zurückkehren können:

[TestFixture] 
class Tests 
{ 
    [Test] 
    public void AddAAATest() 
    { 
     // Arrange 
     Mock<ISecondDeep> secondDeep = new Mock<ISecondDeep>(); 
     secondDeep.Setup(x => x.SomethingToDo(It.IsAny<string>())).Returns(true); 
     // Act 
     FirstDeep fd = new FirstDeep(secondDeep.Object); 
     // Assert 
     Assert.That(fd.AddA("ABD"), Is.EqualTo("ABCAAA")); 
    } 
}