2016-04-04 6 views
1

Lassen Sie uns sagen, ich habe Methoden A, B, C und D.überspringen innere Methodenaufrufe in Unit-Tests

public bool A (int foo) 
{ 
    bool result = false; 
    if (foo > 0) 
     result = B(); 
    else result = C(); 
    D(foo); 
    return result; 
} 

Ich möchte ein Unit-Test für A schreiben, mit B oder C Aufruf, sondern wollen Überspringen Sie den D-Aufruf (weil es eine Methode ist, die externe Dienste verwendet). Ist es möglich, den D-Aufruf mit einigen Attributen zu überspringen? Oder die D verspotten und sie durch einen falschen Dienst ersetzen?

+0

Sie müssen * Mock * 'D': Sie können nicht vermeiden,' D' aufzurufen, wenn Sie 'A' Methode eingeben –

+0

Ja, Sie müssen Mock * D *. – bit

+0

In beiden Fällen ist Ihr Wunsch, den 'D'-Anruf zu überspringen, das Problem selbst. Sie möchten Ihr Gerät nicht verändern, sonst ist es kein echter Test. Ihr Test sollte die Codeeinheit als eine Art Blackbox behandeln. "Ich gebe diesen Input, ich erwarte diesen Output." –

Antwort

1

Sie müssen festlegen, dass die Klasse mit der Methode A() von den externen Diensten abhängig ist, die von der Methode D() verwendet werden. Sie können dazu jedes der DI-Muster verwenden, obwohl die Konstruktorinjektion wahrscheinlich der beste Ausgangspunkt ist.

Sobald Sie in dieser Situation sind, kann der externe Dienst (en) D() hängt davon ab, gefälscht und in die Klasse injiziert werden. Das Testen unterliegt nun Ihrer Kontrolle durch das Verhalten der Fälschung (en).

Etwas wie:

class Thing 
{ 
    private IExternalService _externalService; 

    public Thing(IExternalService externalService) 
    { 
     _externalService = externalService; 
    } 

    public void A() { ... } 

    public void D(string foo) 
    { 
     _externalService.DoSomeStuff(); 
    } 
} 

Dann:

[Fact] 
public void TestThisOut() 
{ 
    var fakeExternalService = new MockFramework.CreateMock(); 
    fakeExternalService 
     .ShouldDoSomethingWhen(s => s.DoSomeStuff()) 
     .IsCalled(); 

    var testThing = new Thing(fakeExternalService); 

    testThing.A(); 

    Assert.That(testThing, Did.Some.Thing()); 
} 
1

Dies zeigt, wie wichtig es ist, Ihren Code so zu entwerfen, dass er testbar ist. Die Abhängigkeitsinjektion ist in dieser Hinsicht sehr nützlich. Sie können dann Abhängigkeiten beim Komponententest nachbilden. Möglicherweise verfügen Sie über eine Kommunikationsschicht, auf die Sie beispielsweise über eine Schnittstelle ICommunications zugreifen können. Ihre Klasse würde dann einen Verweis auf ein ICommunications Objekt in seiner contructor:

public class TestableClass 
{ 
    private ICommunications _comms; 
    public TestableClass(ICommunications comms) 
    { 
     _comms = comms; 
    } 

    public bool FunctionToTest() 
    { 
     //do something testable 

     _comms.SomeFunction();//mocked object in unit tests 

     //do something else testable 
    } 
} 

Dann nur eine Mock-Version von Comms erstellen und passiert in während des Tests. Sie können Ihrer verspotteten Klasse auch Code hinzufügen, um bestimmte Testbedingungen zu emulieren - z. B. wenn eine Kommunikationsschicht ungültige Daten empfängt.

0

Sie müssen Methode verspotten D. ich ein Beispiel schrieb, Typemock Trenner verwenden, werfen Sie einen Blick:

class Methods 
{ 
    public bool A(int foo) 
    { 
     bool result = false; 
     if (foo > 0) 
      result = B(); 
     else 
      result = C(); 
     D(foo); 
     return result; 
    } 

    public void D(int foo) {throw new NotImplementedException();} 

    public bool C() { return false;} 

    public bool B() { return true;} 
} 

Und der Test:

[TestMethod, Isolated] 
public void TestIgnoreD() 
{ 
    //Arrange 
    Methods methods = new Methods(); 
    Isolate.WhenCalled(() => methods.D(0)).IgnoreCall(); 

    //Act 
    bool result = methods.A(1); 

    //Assert 
    Assert.IsTrue(result); 
} 

Ich lege sie alle in eine Klasse, nur weil ich nicht weiß, was in Ihrem Code vorgeht. Anyway, Isolator ziemlich flexibel, da es fast alles von fast überall zu verspotten erlaubt.