未被模拟对象抛出的异常
本文关键字:异常 对象 模拟 | 更新日期: 2023-09-27 18:17:00
目标是单元测试PUBLIC VOID方法。
我有一个mock服务,我的class-under-test将在for-each循环中使用3个不同的参数调用它。
被测试类将一些输入参数传递给使用这些参数执行的服务的"SendRequest"方法。
我希望被模拟的服务在其中一个参数具有特定值时抛出异常,例如"abc"。我使用如下代码:
public class ClassUnderTest
{
private IMyService _myservice;
public ClassUnderTest(IMyService myservice)
{
_myservice = myservice;
}
public void MyMethod()
{
//assume I get those 3 values from somewhere, in here.
var list = new List<string>{"abc","aaa","bbb"};
foreach(var item in list)
{
try
{
_myservice.SendRequest(item);
}
catch(Exception ex)
{
//do some logging and continue calling service with next item in list
}
}
}
}
var myService = new Mock<IMyService>();
myService.Setup(x => x.SendRequest("abc")).Throws<Exception>();
myService.Setup(x => x.SendRequest("aaa"));
myService.Setup(x => x.SendRequest("bbb"));
var classUnderTest = new ClassUnderTest(myService.Object);
classUnderTest.MyMethod();
myService.Verify(x =>x.SendRequest(It.IsAny<string>()), Times.Exactly(2));
更多上下文:由于MyMethod返回void,为了测试它,我只能依赖于在该方法中代码的不同部分调用我的依赖项这一事实。例如,如果在服务调用之前对输入参数进行空检查,则该方法将在调用服务之前返回。如果它通过了null检查,则将调用依赖项服务。我将能够在代码覆盖结果中(以及在调试模式下)跟踪这些。
当我运行测试时,它失败了,因为它调用了三次服务,但我期望调用发生两次(现在可能是我错了,可能是,虽然它应该抛出异常,调用尝试仍然被Verify调用计数,因此我得到3次运行)。
无论如何,在调试中我看到服务从来没有抛出异常。我在for-each循环中有一个try-catch,我想在其中做一些日志记录,并使用下一个值再次继续调用服务。但是我从来没有进入Catch块。
我做错了什么?
选项1:特定例外
我的第一个建议是抛出一个更具体的异常,这样你可以更确定。
选项2:注入ILogger服务
将日志重构到一个iloglogger中,并将其注入。然后传入一个mock,并对它进行断言。
选项3:提取和覆盖
如果必须检查catch块是否被击中,可以使用extract和override:
public class ClassUnderTest
{
private IMyService _myservice;
public ClassUnderTest(IMyService myservice)
{
_myservice = myservice;
}
public void MyMethod()
{
//assume I get those 3 values from somewhere, in here.
var list = new List<string>{"abc","aaa","bbb"};
foreach(var item in list)
{
try
{
_myservice.SendRequest(item);
}
catch(Exception ex)
{
LogError(ex);
}
}
}
protected virtual LogException(Exception ex)
{
//do logging
}
}
public class TestableClassUnderTest : ClassUnderTest
{
public bool LoggingWasCalled { get; set; }
protected virtual LogException(Exception ex)
{
LoggingWasCalled = true;
}
}
然后你可以像这样:
var testableSut = new TestableClassUnderTest ();
testableSut.MyMethod("abc");
Assert.True(testableSut.LoggingWasCalled);
我在这里更详细地介绍一下:http://devonburriss.me/testing-the-untestable/