我试图设计一个单元测试来测试重试循环模式。我能想到的唯一方法就是在测试中途改变嵌入在重试循环中心的方法所返回的内容。
例如......我想在测试的前5秒内为特定方法抛出异常。然后停止抛出该异常,并在该点之后实际响应一些有效数据。
前5秒:
service.MethodToRetry(Arg.Any<string>()).ThrowsForAnyArgs(new Exception());
之后,异常条件被删除,MethodToRetry()正常完成。
这是可能的还是我完全以错误的方式解决这个问题?我在c#中使用xunit和nsubstitute。
答案 0 :(得分:4)
注意:这里的测试是为了证明NSubstitute的行为。在实际测试中,我们不会测试替代品。 :)
测试重试的一种方法是存根多次返回(如果您需要条件而不是针对特定数量的调用失败,这可能不适用于您的情况,但我认为我会从最简单的方法开始):< / p>
[Test]
public void StubMultipleCalls() {
Func<string> throwEx = () => { throw new Exception(); };
var sub = Substitute.For<IThingoe>();
// Stub method to fail twice, then return valid data
sub.MethodToRetry(Arg.Any<string>())
.Returns(x => throwEx(), x => throwEx(), x => "works now");
// The substitute will then act like this:
Assert.Throws<Exception>(() => sub.MethodToRetry(""));
Assert.Throws<Exception>(() => sub.MethodToRetry(""));
Assert.AreEqual("works now", sub.MethodToRetry(""));
// Will continue returning last stubbed value...
Assert.AreEqual("works now", sub.MethodToRetry(""));
Assert.AreEqual("works now", sub.MethodToRetry(""));
}
另一种选择是在你打断电话时把条件放进去:
[Test]
public void StubWithCondition() {
var shouldThrow = true;
var sub = Substitute.For<IThingoe>();
sub.MethodToRetry(Arg.Any<string>()).Returns(x => {
if (shouldThrow) {
throw new Exception();
}
return "works now";
});
Assert.Throws<Exception>(() => sub.MethodToRetry(""));
shouldThrow = false; // <-- can alter behaviour by modifying this variable
Assert.AreEqual("works now", sub.MethodToRetry(""));
}
作为此方法的修改版本,您还可以替换用于存根的回调:
[Test]
public void ReplaceLambda() {
Func<string> methodToRetry = () => { throw new Exception(); };
var sub = Substitute.For<IThingoe>();
sub.MethodToRetry(Arg.Any<string>()).Returns(x => methodToRetry());
Assert.Throws<Exception>(() => sub.MethodToRetry(""));
methodToRetry = () => "works now";
Assert.AreEqual("works now", sub.MethodToRetry(""));
}
理想情况下,我们会尝试在测试中避免与时间相关的逻辑,但如果真的有必要,我们可以在5秒后更新第二个示例中的条件,以获得问题中提到的行为。
答案 1 :(得分:0)
所有的拳头,我没有看到任何具体的实施,所以我会把它放在一般。
思想: