2016-06-08 14 views
0

Als ein Unitestneuling, habe ich gelesen, dass ein Test für eine Methode sein sollte.
Also, was ist der Weg für das Testen der Methode DoStuff unten?Einheit, die eine Methode mit mehreren Schnittstellenanrufen prüft

Sind es drei separate Tests, mit richtigen Setup 's für jede Schnittstelle Fall?
Oder ist es ein Test mit Setup 's und Returns, eher wie ein Verhalten?

public class MainClass 
{ 
    IFoo myFoo; 
    IBar myBar; 
    IBaz myBaz; 

    public MainClass(IFoo foo, IBar bar, IBaz baz) { 
     this.myFoo= foo; 
     this.myBar= bar; 
     this.myBaz= baz; 
    } 

    public void DoStuff(string myParam) { 
     var fooResult = myFoo.doFoo(myParam); 
     myBar.doBar(fooResult); 
     myBaz.doBaz(); 
    } 
} 
+0

Unit Test was? Gegen welche Spezifikationen? Ich sehe hier keine Schnittstellen. – Raedwald

+0

IFoo ist eine der Schnittstellen, die beim Testen von DoStuff verspottet werden. – eych

Antwort

1

Ich nehme mir die Freiheit, NSubstitute anstelle von moq zu verwenden, aber Sie können wahrscheinlich den Weg finden, es mit moq selbst zu tun. Ich werde auch AutoFixture.Xunit2 verwenden, weil es großartig ist.

private MainClass _target; 
private IFoo _foo = Substitue.For<IFoo>(); 
private IBar _bar = Substitute.For<IBar>(); 
private IBaz _baz = Substitute.For<IBaz>(); 

public MainClassTest() 
{ 
    _target = new MainClass(_foo, _bar, _baz); 
} 

[Theory, AutoData] 
public void DoStuff_Delegates_To_Foo(string myParam) 
{ 
    _target.DoStuff(myParam); 
    _foo.Received.DoFoo(Arg.Is(myParam)); 
} 

[Theory, AutoData] 
public void DoStuff_Calls_Bar_With_Result_From_Foo(string myParam, object fooResult) 
{ 
    _foo.DoFoo(Arg.Is(myParam)).Returns(fooResult); 

    _target.DoStuff(myParam); 

    _bar.Received().DoBar(Arg.Is(fooResult)); 
} 

[Theory, AutoData] 
public void DoStuff_Calls_Baz_After_Foo_And_Bar(string myParam) 
{ 
    _target.DoStuff(myParam); 

    Received.InOrder(() => 
    { 
     _foo.DoFoo(Arg.Any<string>()); 
     _bar.DoBar(Arg.Any<object>()); 
     _baz.DoBaz(); 
    } 
} 

Die Idee ist, ein Testverfahren für jede Sache, die Sie über die DoStuff Methode wissen wollen, haben. Die oben genannten sind nur Beispiele, wenn Sie möchten, können Sie auch alles in einem Test schreiben. Hier besteht die Herausforderung darin, eine gute Beschreibung dessen zu finden, was Sie testen (also stellen Sie sich vor, Sie benennen den Test, und Ihr Kollege implementiert es), hier folgt ein Beispiel für eine schlecht benannte Testmethode, die alles testet.

[Theory, AutoData] 
public void DoStuff_Does_What_It_Is_Supposed_To_Do(string myParam, object fooResult) 
{ 
    _foo.DoFoo(Arg.Is(myParam)).Returns(fooResult); 

    _target.DoStuff(myParam); 

    Received.InOrder(() => 
    { 
     _foo.DoFoo(Arg.Is(myParam)); 
     _bar.DoBar(Arg.Is(fooResult)); 
     _baz.DoBaz(); 
    } 
} 

Um Ihre Frage zu beantworten, kommt es auf die Benennung an. Wenn Sie den Test in einem kurzen Satz beschreiben können, dann machen Sie es. Sie haben wahrscheinlich gehört, dass jede Testmethode eine Sache und nur eine Sache testen sollte, und es hilft, wenn Sie "Sache" in diesem Zusammenhang als etwas betrachten, das Sie in einem einzigen kurzen Satz beschreiben können.

1

Ich habe gelesen, dass ein Test sollte für eine Methode sein

Das ist nicht wahr. Möglicherweise verfügen Sie über mehrere Komponententests für eine Methode.

In "DoStuff" gibt es keine echte Verhalten/Logik abgesehen von dem Aufruf von MyFoo und MyBar.

Es gibt nicht viel Wert, den Sie erhalten Einheit Diese routinemäßige IMO testen. Sehr ähnlich zu einem Serviceaufruf, der Routinen orchestriert.