【发布时间】:2011-10-26 02:34:59
【问题描述】:
使用 Moq 模拟一个在第一次调用时会抛出异常,然后在第二次调用时成功的方法的最简洁的方法是什么?
【问题讨论】:
-
Moq 4.2 及更高版本现在通过
SetupSequence()支持此功能。
标签: c# unit-testing mocking nunit moq
使用 Moq 模拟一个在第一次调用时会抛出异常,然后在第二次调用时成功的方法的最简洁的方法是什么?
【问题讨论】:
SetupSequence() 支持此功能。
标签: c# unit-testing mocking nunit moq
到目前为止,我想出的最好的是:
interface IFoo
{
void Bar();
}
[Test]
public void TestBarExceptionThenSuccess()
{
var repository = new MockRepository(MockBehavior.Default);
var mock = repository.Create<IFoo>();
mock.Setup(m => m.Bar()).
Callback(() => mock.Setup(m => m.Bar())). // Setup() replaces the initial one
Throws<Exception>(); // throw an exception the first time
...
}
【讨论】:
mock.Verify(m => m.Bar(), Times.Exactly(2))。
我会使用Callback 并增加一个计数器来确定是否从Callback 抛出异常。
[Test]
public void TestMe()
{
var count = 0;
var mock = new Mock<IMyClass>();
mock.Setup(a => a.MyMethod()).Callback(() =>
{
count++;
if(count == 1)
throw new ApplicationException();
});
Assert.Throws(typeof(ApplicationException), () => mock.Object.MyMethod());
Assert.DoesNotThrow(() => mock.Object.MyMethod());
}
public interface IMyClass
{
void MyMethod();
}
【讨论】:
reader.Setup(r => r.Read()).ReturnsInOrder(true, true, false);
SetupSequence 肯定更容易、更优雅。检查@aghidini 的答案。
Phil Haack 有一个有趣的blog post 来设置一个返回特定结果序列的方法。看起来这将是一个很好的起点,涉及一些工作,因为您现在需要的不是特定类型的值序列,而是可能是 T 类型或异常的结果序列。
【讨论】:
从 Moq 4.2 开始,您可以只使用内置方法 SetupSequence()(如 @RichardBarnett 评论所述)。
例子:
var mock = new Mock<IMyClass>();
mock.SetupSequence(x => x.MyMethod("param1"))
.Throws<MyException>()
.Returns("test return");
【讨论】:
MyMethod 具有返回类型时才有效。如果方法是void,那么你不能使用这种方法。如果有办法用void 方法做到这一点会很好