对具有多个接口调用的方法进行单元测试
Unit testing a method with multiple interface calls
作为单元测试新手,我一直在读到一个测试应该针对一种方法。
那么,下面的方法DoStuff
的测试方法是什么?
它是三个独立的测试,每个接口案例都有适当的 Setup
吗?
或者,它是 Setup
和 Returns
的一项测试,更像是 Strict
行为吗?
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();
}
}
I've been reading that one test should be for one method
这不是真的。一个方法可能有多个单元测试。
在“DoStuff
”中,除了调用myFoo和myBar之外,没有真正的behavior/logic。
在 IMO 中,单元测试没有多大价值。
非常类似于编排例程的服务调用。
我冒昧地使用 NSubstitute 而不是最小起订量,但您或许可以自己想出使用最小起订量的方法。我还将使用 AutoFixture.Xunit2,因为它很棒。
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();
}
}
我们的想法是为您想知道的关于 DoStuff
方法的每一件事都提供一个测试方法。以上只是示例,如果你愿意也可以一次测试全部写完。这里的挑战是对您测试的内容提出一个很好的描述(假设您为测试命名并且您的同事实现了它),无论如何,这里有一个命名错误的测试方法的示例,它测试所有内容。
[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();
}
}
因此,要回答您的问题,归结为命名。如果你能用一个简短的句子描述测试,那就去做吧。您可能听说过每种测试方法都应该测试一件事,而且只能测试一件事,如果您在这种情况下将 "thing" 视为可以用一个简短的句子描述的东西,它会有所帮助。
作为单元测试新手,我一直在读到一个测试应该针对一种方法。
那么,下面的方法DoStuff
的测试方法是什么?
它是三个独立的测试,每个接口案例都有适当的 Setup
吗?
或者,它是 Setup
和 Returns
的一项测试,更像是 Strict
行为吗?
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();
}
}
I've been reading that one test should be for one method
这不是真的。一个方法可能有多个单元测试。
在“DoStuff
”中,除了调用myFoo和myBar之外,没有真正的behavior/logic。
在 IMO 中,单元测试没有多大价值。 非常类似于编排例程的服务调用。
我冒昧地使用 NSubstitute 而不是最小起订量,但您或许可以自己想出使用最小起订量的方法。我还将使用 AutoFixture.Xunit2,因为它很棒。
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();
}
}
我们的想法是为您想知道的关于 DoStuff
方法的每一件事都提供一个测试方法。以上只是示例,如果你愿意也可以一次测试全部写完。这里的挑战是对您测试的内容提出一个很好的描述(假设您为测试命名并且您的同事实现了它),无论如何,这里有一个命名错误的测试方法的示例,它测试所有内容。
[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();
}
}
因此,要回答您的问题,归结为命名。如果你能用一个简短的句子描述测试,那就去做吧。您可能听说过每种测试方法都应该测试一件事,而且只能测试一件事,如果您在这种情况下将 "thing" 视为可以用一个简短的句子描述的东西,它会有所帮助。