本文共 2143 字,大约阅读时间需要 7 分钟。
有时当收到一个特殊的调用时能执行一些代码是非常有用的。我们在一节已经看到了类似的代码。
public interface ICalculator { int Add(int a, int b); string Mode { get; set; } } [TestMethod] public void Test_CallbacksWhenDo_PassFunctionsToReturns() { var calculator = Substitute.For(); var counter = 0; calculator .Add(0, 0) .ReturnsForAnyArgs(x => 0) .AndDoes(x => counter++); calculator.Add(7, 3); calculator.Add(2, 2); calculator.Add(11, -3); Assert.AreEqual(counter, 3); }
关于传递函数参数,在这一节有更详细的介绍。
Returns() 可以被用于为成员设置产生返回值的回调函数,但是对于 void 类型的成员,我们需要不同的方式,因为我们无法调用一个 void 并返回一个值。对于这种情况,我们可以使用 When..Do 语法。
When..Do 使用两个调用来配置回调。首先,调用替代实例的 When() 方法来传递一个函数。该函数的参数是替代实例自身,然后此处我们可以调用我们需要的成员,即使该成员返回 void。然后再调用 Do() 方法来传递一个回调,当替代实例的成员被调用时,执行这个回调。
1 public interface IFoo 2 { 3 void SayHello(string to); 4 } 5 6 [TestMethod] 7 public void Test_CallbacksWhenDo_UseWhenDo() 8 { 9 var counter = 0;10 var foo = Substitute.For();11 12 foo.When(x => x.SayHello("World"))13 .Do(x => counter++);14 15 foo.SayHello("World");16 foo.SayHello("World");17 Assert.AreEqual(2, counter);18 }
传递给 Do() 方法的参数中包含的调用信息与中的相同,这些调用信息可以用于对参数进行访问。
注意,我们也可以对非 void 成员使用 When..Do 语法,但是,通常来说更加推荐 Returns() 语法,因为其更加简洁明确。你可能会发现,对于非 void 函数,当你想执行一个函数而不改变之前的返回值时,这个功能是非常有用的。
[TestMethod] public void Test_CallbacksWhenDo_UseWhenDoOnNonVoid() { var calculator = Substitute.For(); var counter = 0; calculator.Add(1, 2).Returns(3); calculator .When(x => x.Add(Arg.Any (), Arg.Any ())) .Do(x => counter++); var result = calculator.Add(1, 2); Assert.AreEqual(3, result); Assert.AreEqual(1, counter); }
如果在某些地方,我们仅需要对一个特殊的参数创建回调,则我们可能会使用,例如 Arg.Do() 和 Arg.Invoke(),而不是使用 When..Do。
参数回调给予我们更加简洁的代码,NSubstitute 中的其他 API 也保持这一风格。更多信息和示例,请查看一节。