我在我的测试中有以下结构,旨在测试是否使用正确的复杂参数对象调用某个日志,即使它引发异常,然后将其包装并通常进一步操作。logThing 有一个方法:
void AddEntry(LogEntry);
所以我使用 When..Do 让它抛出异常,
public void UnitTest()
{
// Arrange
ILogThing logThing = Substitute.For<ILogThing>()
SystemUnderTest system = new SystemUnderTest(logThing);
List<LogEntry> actualEntries = new List<LogEntry>();
LogEntry expectedEntry = GetSomeTestData();
logThing.When(
lt => lt.AddEntry(Arg.Do<LogEntry>(r => actualEntries.Add(r)))).Do(
call => { throw new InvalidOperationException("testMessage"); });
// Act
try
{
system.DoSomethingWhichLogs(someArgs)
}
catch(WrappedException ex)
{
// Assert
Assert.AreEqual(1, actualEntries.Count);
Assert.AreEqual(actualEntries[0], expectedEntry);
}
}
但是,此设置不会发生对 Arg.Do() 的预期调用。
我在 catch 块中放置了一个断点,并使用 Visual Studio 的即时窗口在 logThing 上调用 RecievedCalls<>(),它确实记录了一次使用正确参数调用 logThing 的记录——这就是 Arg.Do似乎只在 When..Do 块完成后执行。显然,这意味着由于我正在投入When..Do,它永远不会到达它。
我真的没想到 NSubstitute 会以这种方式订购电话,这是预期的行为吗?如果是这样,我可以做些什么来测试这样的传入参数,还是应该将我的参数检查放入主 When..Do 块中(这使得它更难阅读)?
被测系统对异常做了各种处理,包括将其与 logEntry 一起包装,因此在一个测试中进行所有这些检查对我很有用 - 我确实考虑过将它分成两个单独的测试,但意识到如果我这样做了,我将无法轻易确定错误包装输出的来源(它可能是最初生成 logEntry 的部分,也可能是包装它的部分)而我可以检查以确保使用此模式logThing 正在接收我所期望的。不过,如果有更好的方法可以做到这一点,我当然愿意接受建议。