我在C#中有一个名为MyService
的Wrapper类用于ThirdPartyService
API。我想为此MyService
创建一些测试,以确保我按预期处理所有案例。
ThirdPartyService
具有以下公开的方法,我们通过MyService
包装器在不同的地方使用这些方法。
MethodToCreate
由于它是第三方服务,我不知道其中包含的业务逻辑。因此,我无法直接为该服务创建测试双,因为它是我们使用的库。
然而,当发生不同类型的不良事件时,第三方库经常会返回错误,例如
当事情正常时,它也会返回实际结果。
我想创建一个MyServiceTestDouble
类来帮助我测试与ThirdPartyService案例的每种类型的交互。
所以IMyService
和MyService
看起来像这样(只是一个例子,只有一种方法):
public interface IMyService
{
int MethodToCreate(string arg1, string arg2);
}
public class MyService : IMyService
{
private readonly ThirdPartyService _thirdPartyService;
public MyService()
{
_thirdPartyService = new ThirdPartyService();
}
public int MethodToCreate(string arg1, string arg2)
{
var thirdPartyServiceTypeArg = ParseStringToThirdPartyServiceArg(arg1);
return _thirdPartyService.MethodToCreate(thirdParthyServiceTypeArg, arg2);
}
}
public class MyServiceTestDouble : IMyService
{
public MyServiceTestDouble()
{
}
public int MethodToCreate(string arg1, string arg2)
{
return (new Random).Next();
}
}
public static class MyServiceFactory
{
public static IMyService GetMyService()
{
if(!Config.IsTestMode) return new MyService();
return new MyServiceTestDouble();
}
}
但我已经陷入需要根据我的单元测试使MyServiceTestDouble
中的方法返回不同类型的输出的位置。
就像我正在测试的情况一样,我希望它能够返回正确的实际结果。
当我的测试用例用于测试异常时,我希望MyServiceTestDouble
中的方法返回适当的异常。
这样做的最佳方法是什么?
我认为可行的一种方法是创建一个MyServiceFactory
,它根据Unit测试用例场景返回不同的Test Double Implementations。但这意味着我需要MyServiceTestDouble
的多个实现,如MyServiceTestDoubleGood
。 MyServiceTestDoubleNetworkExceptions
,MyServiceTestOutageExceptions
等
我很确定我可能还有一种更好的方式,而我目前还没有意识到这一点。
我想知道是否有任何单元测试框架可以帮助进行此类测试。
我还想知道在不使用任何框架的情况下是否可以以更优雅的方式实现这一点。
答案 0 :(得分:2)
更好的解决方案是使用moq
库,它具有根据特殊输入值返回数据或不同类型异常的简写方法。所以你可以说,如果输入为1,则抛出一个错误;如果输入是3,则返回数据等。
安装为here
Getting Started有一些例子:
using Moq;
var mockMyService = new Mock<IMyService>();
mockMyService.Setup(o => o.MethodToCreate("arg1", "arg2")).Returns(4);
mockMyService.Setup(o => o.MethodToCreate("cut","cable")).Throws(new NetworkException("the network is down"));
或者,您可以使用switch语句模拟虚拟类中moq的这个功能:
public int MethodToCreate(string arg1, string arg2)
{
switch(arg1){
case "a":
throw new Exception(); // throw exception
case "z":
return 4; // good data
}
}