我有一个类似的课程:
public class MyClass
{
public Task MyMethod()
{
//do something
}
}
如上所述,'MyMethod'是异步的,为简单起见,这就是它的实现:
public Task MyMethod()
{
return Task.Run(() =>
{
var success = _someService.DoSomething();
if (!success) throw new Exception("unsuccsesfull");
});
}
显然,当MyMethod等待回调将运行时,意味着在正在运行的线程中没有抛出任何异常,这意味着“MyMethod”调用成功。
我想测试一下这个方法。测试方法如下:
[Test]
public async void TestMyMethod_TestInitialState_TestExpectedResult()
{
// test initialization..
//...
//..
var myClass = new MyClass();
await myClass.MyMethod();
Assert.That(????)
}
我的问题 - 什么是正确的断言?
我有一个可能的解决方案 - 将一个逻辑成员添加到'MyClass'并根据方法结果更新该成员:
public class MyClass
{
public bool SomeMember { get; private set; }
public Task MyMethod()
{
Task.Run(() =>
{
SomeMember = _someService.DoSomething();
if (!SomeMember ) throw new Exception("unsuccsesfull");
});
}
}
这样我可以像这样断言测试:
[Test]
public async void TestMyMethod_TestInitialState_SomeMemberShouldBeTrue()
{
// test initialization..
//...
//..
var myClass = new MyClass();
await myClass.MyMethod();
Assert.True(SomeMember)
}
}
但是,我不喜欢这个解决方案,因为我正在为'MyClass'添加一个属性,只是为了能够断言测试,我真的不需要在我的商业世界中使用这个属性。此外,添加到类中的每个属性都代表此类的某些状态,并增加了一定程度的复杂性。
建议?
盖。
答案 0 :(得分:3)
你想要的是“模拟”或“存根”。我们的想法是你重构代码,使它依赖于接口,然后在测试时模拟接口。
有各种框架/工具可以帮助进行模拟(Moq,Microsoft Fakes,TypeMock Isolator,JustMock等),并且还有许多框架可以帮助解决依赖注入密切相关的问题(Unity,Castle Windsor) ,StructureMap,Autofac等)。
但你可以自己开始做。首先,重构MyClass
因此取决于ISomeService
:
public interface ISomeService
{
bool DoSomething();
}
public class MyClass
{
private readonly ISomeService _someService;
public MyClass(ISomeService someService)
{
_someService = someService;
}
public Task MyMethod()
{
return Task.Run(() =>
{
var success = _someService.DoSomething();
if (!success) throw new Exception("unsuccsesfull");
});
}
}
然后在你的单元测试中:
private class TestService : ISomeService
{
public bool DoSomethingReturnValue { get; set; }
public bool DoSomething() { return DoSomethingReturnValue; }
}
[Test]
public async Task TestMyMethod_TestInitialState_TestExpectedResult()
{
var myClass = new MyClass(new TestService { DoSomethingReturnValue = true });
await myClass.MyMethod();
}
[Test]
public async Task TestMyMethod_TestInitialState_TestFailure()
{
var myClass = new MyClass(new TestService { DoSomethingReturnValue = false });
Assert.Throws(() => myClass.MyMethod()); // (I'm unsure of the exact NUnit syntax)
}