本文共 6645 字,大约阅读时间需要 22 分钟。
在某些情况下(尤其是对void方法),检测替代实例是否能成功接收到一个特定的调用是非常有用的。可以通过使用 Received() 扩展方法,并紧跟着被检测的方法。
1 public interface ICommand 2 { 3 void Execute(); 4 event EventHandler Executed; 5 } 6 7 public class SomethingThatNeedsACommand 8 { 9 ICommand command;10 public SomethingThatNeedsACommand(ICommand command)11 {12 this.command = command;13 }14 public void DoSomething() { command.Execute(); }15 public void DontDoAnything() { }16 }17 18 [TestMethod]19 public void Test_CheckReceivedCalls_CallReceived()20 {21 //Arrange22 var command = Substitute.For();23 var something = new SomethingThatNeedsACommand(command);24 25 //Act26 something.DoSomething();27 28 //Assert29 command.Received().Execute();30 }
在这个例子中,command 收到了一个对 Execute() 方法的调用,所以会顺利地完成。如果没有收到对 Execute() 的调用,则 NSubstitute 会抛出一个 ReceivedCallsException 异常,并且会显示具体是在期待什么方法被调用,参数是什么,以及列出实际的方法调用和参数。
1 [TestMethod] 2 public void Test_CheckReceivedCalls_CallDidNotReceived() 3 { 4 //Arrange 5 var command = Substitute.For(); 6 var something = new SomethingThatNeedsACommand(command); 7 8 //Act 9 something.DontDoAnything();10 11 //Assert12 command.DidNotReceive().Execute();13 }
1 public class CommandRepeater 2 { 3 ICommand command; 4 int numberOfTimesToCall; 5 public CommandRepeater(ICommand command, int numberOfTimesToCall) 6 { 7 this.command = command; 8 this.numberOfTimesToCall = numberOfTimesToCall; 9 }10 11 public void Execute()12 {13 for (var i = 0; i < numberOfTimesToCall; i++) command.Execute();14 }15 }16 17 [TestMethod]18 public void Test_CheckReceivedCalls_CallReceivedNumberOfSpecifiedTimes()19 {20 // Arrange21 var command = Substitute.For();22 var repeater = new CommandRepeater(command, 3);23 24 // Act25 repeater.Execute();26 27 // Assert28 // 如果仅接收到2次或者4次,这里会失败。29 command.Received(3).Execute();30 }
Received(1) 会检查该调用收到并且仅收到一次。这与默认的 Received() 不同,其检查该调用至少接收到了一次。Received(0) 的行为与 DidNotReceive() 相同。
1 public interface ICalculator 2 { 3 int Add(int a, int b); 4 string Mode { get; set; } 5 } 6 7 [TestMethod] 8 public void Test_CheckReceivedCalls_CallReceivedWithSpecificArguments() 9 {10 var calculator = Substitute.For();11 12 calculator.Add(1, 2);13 calculator.Add(-100, 100);14 15 // 检查接收到了第一个参数为任意值,第二个参数为2的调用16 calculator.Received().Add(Arg.Any (), 2);17 // 检查接收到了第一个参数小于0,第二个参数为100的调用18 calculator.Received().Add(Arg.Is (x => x < 0), 100);19 // 检查未接收到第一个参数为任意值,第二个参数大于等于500的调用20 calculator21 .DidNotReceive()22 .Add(Arg.Any (), Arg.Is (x => x >= 500));23 }
1 [TestMethod] 2 public void Test_CheckReceivedCalls_IgnoringArguments() 3 { 4 var calculator = Substitute.For(); 5 6 calculator.Add(1, 3); 7 8 calculator.ReceivedWithAnyArgs().Add(1, 1); 9 calculator.DidNotReceiveWithAnyArgs().Subtract(0, 0);10 }
1 [TestMethod] 2 public void Test_CheckReceivedCalls_CheckingCallsToPropeties() 3 { 4 var calculator = Substitute.For(); 5 6 var mode = calculator.Mode; 7 calculator.Mode = "TEST"; 8 9 // 检查接收到了对属性 getter 的调用10 // 这里需要使用临时变量以通过编译11 var temp = calculator.Received().Mode;12 13 // 检查接收到了对属性 setter 的调用,参数为"TEST"14 calculator.Received().Mode = "TEST";15 }
1 [TestMethod]2 public void Test_CheckReceivedCalls_CheckingCallsToIndexers()3 {4 var dictionary = Substitute.For>();5 dictionary["test"] = 1;6 7 dictionary.Received()["test"] = 1;8 dictionary.Received()["test"] = Arg.Is (x => x < 5);9 }
1 public class CommandWatcher 2 { 3 ICommand command; 4 public CommandWatcher(ICommand command) 5 { 6 this.command = command; 7 this.command.Executed += OnExecuted; 8 } 9 public bool DidStuff { get; private set; }10 public void OnExecuted(object o, EventArgs e) 11 { 12 DidStuff = true; 13 }14 } 15 16 [TestMethod]17 public void Test_CheckReceivedCalls_CheckingEventSubscriptions()18 {19 var command = Substitute.For();20 var watcher = new CommandWatcher(command);21 22 command.Executed += Raise.Event();23 24 Assert.IsTrue(watcher.DidStuff);25 }
当然,如果需要的话,Received() 会帮助我们断言订阅是否被收到:
1 [TestMethod] 2 public void Test_CheckReceivedCalls_MakeSureWatcherSubscribesToCommandExecuted() 3 { 4 var command = Substitute.For(); 5 var watcher = new CommandWatcher(command); 6 7 // 不推荐这种方法。 8 // 更好的办法是测试行为而不是具体实现。 9 command.Received().Executed += watcher.OnExecuted;10 // 或者有可能事件处理器是不可访问的。11 command.Received().Executed += Arg.Any ();12 }