• .NET测试--模拟框架NSubstitute


    .NET测试--模拟框架NSubstitute

    NSubstitute在GitHub的开源地址:https://github.com/nsubstitute/nsubstitute/downloads

    入门

    现在假设我们有一个基本的计算器界接口:

    1. public interface ICalculator 

    2. int Add(int a, int b)
    3. string Mode { get; set; } 
    4. event EventHandler PoweringUp; 

    使用NSubstitute创建一个替代实例。
    我们可以使用stub(存根)、mock(模拟)、fake、spy、test double等。

    1. calculator = Substitute.For<ICalculator>(); 

    现在我们可以使用calculator对象返回一个计算值:

    1. calculator.Add(1, 2).Returns(3); 
    2. Assert.That(calculator.Add(1, 2), Is.EqualTo(3)); 

    检测calculator对象是否执行了一个方法调用,没有执行其他的调用:

    1. calculator.Add(1, 2); 
    2. calculator.Received().Add(1, 2);//是否执行了调用 
    3. calculator.DidNotReceive().Add(5, 7);//是否没有执行调用 

    使用Returns方法,返回执行调用的返回值。

    1. calculator.Mode.Returns("DEC"); 
    2. Assert.That(calculator.Mode, Is.EqualTo("DEC")); 
    3.  
    4. calculator.Mode = "HEX"
    5. Assert.That(calculator.Mode, Is.EqualTo("HEX")); 

    NSubstitute 支持设置输入参数匹配:

    1. calculator.Add(10, -5); 
    2. calculator.Received().Add(10, Arg.Any<int>());//任何int参数 
    3. calculator.Received().Add(10, Arg.Is<int>(x => x < 0));//第二个参数小于零 

    使用参数匹配以及讲函数传递给Returns方法:

    1. calculator 
    2. .Add(Arg.Any<int>(), Arg.Any<int>()) 
    3. .Returns(x => (int)x[0] + (int)x[1]); 
    4. Assert.That(calculator.Add(5, 10), Is.EqualTo(15)); 

    Returns方法返回多参数序列:

    1. calculator.Mode.Returns("HEX", "DEC", "BIN"); 
    2. Assert.That(calculator.Mode, Is.EqualTo("HEX")); 
    3. Assert.That(calculator.Mode, Is.EqualTo("DEC")); 
    4. Assert.That(calculator.Mode, Is.EqualTo("BIN")); 

    引发事件:

    1. bool eventWasRaised = false
    2. calculator.PoweringUp += (sender, args) => eventWasRaised = true
    3. calculator.PoweringUp += Raise.Event(); 
    4. Assert.That(eventWasRaised); 

    创建substitute

    创建一个具有构造函数参数的类的替代:

    1. var someClass = Substitute.For<SomeClassWithCtorArgs>(5, "hello world"); 

    多接口

    1. var command = Substitute.For<ICommand, IDisposable>(); 
    2. var runner = new CommandRunner(command); 
    3.  
    4. runner.RunCommand(); 
    5.  
    6. command.Received().Execute(); 
    7. ((IDisposable)command).Received().Dispose(); 

    可以设置多接口,但是类只能有一个:

    1. var substitute = Substitute.For( 
    2. new[] { typeof(ICommand), typeof(ISomeInterface), typeof(SomeClassWithCtorArgs) }, 
    3. new object[] { 5, "hello world"
    4. ); 
    5. Assert.IsInstanceOf<ICommand>(substitute); 
    6. Assert.IsInstanceOf<ISomeInterface>(substitute); 
    7. Assert.IsInstanceOf<SomeClassWithCtorArgs>(substitute); 

    代理

    1. var func = Substitute.For<Func<string>>(); 
    2. func().Returns("hello"); 
    3. Assert.AreEqual("hello", func()); 

    设置返回值

    1. public interface ICalculator
    2. int Add(int a, int b)
    3. string Mode { get; set; } 

    方法

    1. var calculator = Substitute.For<ICalculator>(); 
    2. calculator.Add(1, 2).Returns(3); 

    调用的参数必须一样,返回值才会固定

    1. //Make a call return 3: 
    2. calculator.Add(1, 2).Returns(3); 
    3. Assert.AreEqual(calculator.Add(1, 2), 3); 
    4. Assert.AreEqual(calculator.Add(1, 2), 3); 
    5.  
    6. //Call with different arguments does not return 3 
    7. Assert.AreNotEqual(calculator.Add(3, 6), 3); 

    属性

    1. calculator.Mode.Returns("DEC"); 
    2. Assert.AreEqual(calculator.Mode, "DEC"); 
    3. calculator.Mode = "HEX"
    4. Assert.AreEqual(calculator.Mode, "HEX"); 

    返回值指定输入具体参数

    1. //Return when first arg is anything and second arg is 5: 
    2. //返回当第一个参数是任意int,第二个参数是5 
    3. calculator.Add(Arg.Any<int>(), 5).Returns(10); 
    4. Assert.AreEqual(10, calculator.Add(123, 5)); 
    5. Assert.AreEqual(10, calculator.Add(-9, 5)); 
    6. Assert.AreNotEqual(10, calculator.Add(-9, -9)); 
    7.  
    8. //Return when first arg is 1 and second arg less than 0: 
    9. //返回当第一个参数是1,第二个参数小于零 
    10. calculator.Add(1, Arg.Is<int>(x => x < 0)).Returns(345); 
    11. Assert.AreEqual(345, calculator.Add(1, -2)); 
    12. Assert.AreNotEqual(345, calculator.Add(1, 2)); 
    13.  
    14. //Return when both args equal to 0: 
    15. //返回当两个参数都等于0 
    16. calculator.Add(Arg.Is(0), Arg.Is(0)).Returns(99); 
    17. Assert.AreEqual(99, calculator.Add(0, 0)); 

    返回值指定输入任意参数

    1. calculator.Add(1, 2).ReturnsForAnyArgs(100);  
    2. Assert.AreEqual(calculator.Add(1, 2), 100); 
    3. Assert.AreEqual(calculator.Add(-7, 15), 100); 

    从一个方法获取返回值

    1. calculator 
    2. .Add(Arg.Any<int>(), Arg.Any<int>()) 
    3. .Returns(x => (int)x[0] + (int)x[1]);//从一个方法获取返回值 
    4.  
    5. Assert.That(calculator.Add(1, 1), Is.EqualTo(2)); 
    6. Assert.That(calculator.Add(20, 30), Is.EqualTo(50)); 
    7. Assert.That(calculator.Add(-73, 9348), Is.EqualTo(9275)); 

    调用信息

    Arg<T>()
    ArgAt<T>(int position)

    1. public interface IFoo
    2. string Bar(int a, string b)

    3.  
    4. var foo = Substitute.For<IFoo>(); 
    5. foo.Bar(0, "").ReturnsForAnyArgs(x => "Hello " + x.Arg<string>()); 
    6. Assert.That(foo.Bar(1, "World"), Is.EqualTo("Hello World")); 

    回调

    1. var counter = 0
    2. calculator 
    3. .Add(0, 0
    4. .ReturnsForAnyArgs(x => { 
    5. counter++; 
    6. return 0
    7. }); 
    8.  
    9. calculator.Add(7,3); 
    10. calculator.Add(2,2); 
    11. calculator.Add(11,-3); 
    12. Assert.AreEqual(counter, 3); 
    1. var counter = 0
    2. calculator 
    3. .Add(0, 0
    4. .ReturnsForAnyArgs(x => 0
    5. .AndDoes(x => counter++);//? 
    6.  
    7. calculator.Add(7,3); 
    8. calculator.Add(2,2); 
    9. Assert.AreEqual(counter, 2); 

    多返回值

    1. calculator.Mode.Returns("DEC", "HEX", "BIN"); 
    2. Assert.AreEqual("DEC", calculator.Mode); 
    3. Assert.AreEqual("HEX", calculator.Mode); 
    4. Assert.AreEqual("BIN", calculator.Mode); 

    多返回值回调

    1. calculator.Mode.Returns(x => "DEC", x => "HEX", x => { throw new Exception(); }); 
    2. Assert.AreEqual("DEC", calculator.Mode); 
    3. Assert.AreEqual("HEX", calculator.Mode); 
    4. Assert.Throws<Exception>(() => { var result = calculator.Mode; }); 

    替换返回值

    1. calculator.Mode.Returns("DEC,HEX,OCT"); 
    2. calculator.Mode.Returns(x => "???"); 
    3. calculator.Mode.Returns("HEX"); 
    4. calculator.Mode.Returns("BIN"); 
    5. Assert.AreEqual(calculator.Mode, "BIN"); 

    检查调用,是否执行,返回

    1. public interface ICommand
    2. void Execute()
    3. event EventHandler Executed; 

    4.  
    5. public class SomethingThatNeedsACommand
    6. ICommand command; 
    7. public SomethingThatNeedsACommand(ICommand command) {  
    8. this.command = command; 

    9. public void DoSomething() { command.Execute(); } 
    10. public void DontDoAnything() { } 

    11.  
    12. [Test] 
    13. public void Should_execute_command()
    14. //Arrange 
    15. var command = Substitute.For<ICommand>(); 
    16. var something = new SomethingThatNeedsACommand(command); 
    17. //Act 
    18. something.DoSomething(); 
    19. //Assert 检查是否执行了这个方法 
    20. command.Received().Execute(); 

    检查一个调用是否未执行(未返回)

    1. var command = Substitute.For<ICommand>(); 
    2. var something = new SomethingThatNeedsACommand(command); 
    3. //Act 
    4. something.DontDoAnything(); 
    5. //Assert 
    6. command.DidNotReceive().Execute(); 

    检查一个调用,返回执行次数

    1. public class CommandRepeater
    2. ICommand command; 
    3. int numberOfTimesToCall; 
    4. public CommandRepeater(ICommand command, int numberOfTimesToCall)
    5. this.command = command; 
    6. this.numberOfTimesToCall = numberOfTimesToCall; 

    7.  
    8. public void Execute() {  
    9. for (var i=0; i<numberOfTimesToCall; i++) command.Execute(); 


    10.  
    11. [Test] 
    12. public void Should_execute_command_the_number_of_times_specified()
    13. var command = Substitute.For<ICommand>(); 
    14. var repeater = new CommandRepeater(command, 3); 
    15. //Act 
    16. repeater.Execute(); 
    17. //Assert 
    18. command.Received(3).Execute(); // << This will fail if 2 or 4 calls were received 

    带特殊参数的返回

    1. calculator.Add(1, 2); 
    2. calculator.Add(-100, 100); 
    3.  
    4. //Check received with second arg of 2 and any first arg: 
    5. calculator.Received().Add(Arg.Any<int>(), 2); 
    6. //Check received with first arg less than 0, and second arg of 100: 
    7. calculator.Received().Add(Arg.Is<int>(x => x < 0), 100); 
    8. //Check did not receive a call where second arg is >= 500 and any first arg: 
    9. calculator 
    10. .DidNotReceive() 
    11. .Add(Arg.Any<int>(), Arg.Is<int>(x => x >= 500)); 

    忽略参数

    1. calculator.Add(1, 3); 
    2.  
    3. calculator.ReceivedWithAnyArgs().Add(1,1); 
    4. calculator.DidNotReceiveWithAnyArgs().Subtract(0,0); 

    检查属性

    1. var mode = calculator.Mode; 
    2. calculator.Mode = "TEST"
    3.  
    4. //Check received call to property getter 
    5. //We need to assign the result to a variable to keep 
    6. //the compiler happy. 
    7. var temp = calculator.Received().Mode; 
    8.  
    9. //Check received call to property setter with arg of "TEST" 
    10. calculator.Received().Mode = "TEST"

    检查索引

    1. var dictionary = Substitute.For<IDictionary<string, int>>(); 
    2. dictionary["test"] = 1
    3.  
    4. dictionary.Received()["test"] = 1
    5. dictionary.Received()["test"] = Arg.Is<int>(x => x < 5); 

    检查订阅事件

    1. public class CommandWatcher
    2. ICommand command; 
    3. public CommandWatcher(ICommand command) {  
    4. command.Executed += OnExecuted; 

    5. public bool DidStuff { get; private set; } 
    6. public void OnExecuted(object o, EventArgs e) { DidStuff = true; } 
    7. }  
    8.  
    9. [Test] 
    10. public void ShouldDoStuffWhenCommandExecutes()
    11. var command = Substitute.For<ICommand>(); 
    12. var watcher = new CommandWatcher(command); 
    13.  
    14. command.Executed += Raise.Event(); 
    15.  
    16. Assert.That(watcher.DidStuff); 

    1. [Test] 
    2. public void MakeSureWatcherSubscribesToCommandExecuted()
    3. var command = Substitute.For<ICommand>(); 
    4. var watcher = new CommandWatcher(command); 
    5.  
    6. // Not recommended. Favour testing behaviour over implementation specifics. 
    7. // Can check subscription: 
    8. command.Received().Executed += watcher.OnExecuted; 
    9. // Or, if the handler is not accessible: 
    10. command.Received().Executed += Arg.Any<EventHandler>(); 

    清除调用

    1. public interface ICommand
    2. void Execute()

    3.  
    4. public class OnceOffCommandRunner
    5. ICommand command; 
    6. public OnceOffCommandRunner(ICommand command)
    7. this.command = command; 

    8. public void Run()
    9. if (command == null) return
    10. command.Execute(); 
    11. command = null


    1. var command = Substitute.For<ICommand>(); 
    2. var runner = new OnceOffCommandRunner(command); 
    3.  
    4. //First run 
    5. runner.Run(); 
    6. command.Received().Execute(); 
    7.  
    8. //Forget previous calls to command 
    9. //清楚前面的调用 
    10. command.ClearReceivedCalls(); 
    11.  
    12. //Second run 
    13. runner.Run(); 
    14. command.DidNotReceive().Execute(); 

    参数匹配

    忽略参数

    1. calculator.Add(Arg.Any<int>(), 5).Returns(7); 
    2.  
    3. Assert.AreEqual(7, calculator.Add(42, 5)); 
    4. Assert.AreEqual(7, calculator.Add(123, 5)); 
    5. Assert.AreNotEqual(7, calculator.Add(1, 7)); 
    6.  
    7.  
    8. formatter.Format(new object()); 
    9. formatter.Format("some string"); 
    10.  
    11. formatter.Received().Format(Arg.Any<object>()); 
    12. formatter.Received().Format(Arg.Any<string>()); 
    13. formatter.DidNotReceive().Format(Arg.Any<int>()); 

    匹配一个参数

    1. calculator.Add(1, -10); 
    2.  
    3. //Received call with first arg 1 and second arg less than 0: 
    4. calculator.Received().Add(1, Arg.Is<int>(x => x < 0)); 
    5. //Received call with first arg 1 and second arg of -2, -5, or -10: 
    6. calculator 
    7. .Received() 
    8. .Add(1, Arg.Is<int>(x => new[] {-2,-5,-10}.Contains(x))); 
    9. //Did not receive call with first arg greater than 10: 
    10. calculator.DidNotReceive().Add(Arg.Is<int>(x => x > 10), -10); 
    11.  
    12. formatter.Format(Arg.Is<string>(x => x.Length <= 10)).Returns("matched"); 
    13.  
    14. Assert.AreEqual("matched", formatter.Format("short")); 
    15. Assert.AreNotEqual("matched", formatter.Format("not matched, too long")); 
    16. // Will not match because trying to access .Length on null will throw an exception when testing 
    17. // our condition. NSubstitute will assume it does not match and swallow the exception. 
    18. Assert.AreNotEqual("matched", formatter.Format(null)); 

    匹配特殊参数

    1. calculator.Add(0, 42); 
    2.  
    3. //This won't work; NSubstitute isn't sure which arg the matcher applies to: 
    4. //calculator.Received().Add(0, Arg.Any<int>()); 
    5.  
    6. calculator.Received().Add(Arg.Is(0), Arg.Any<int>()); 
    7.  

    使用参数匹配

    1. /* ARRANGE */ 
    2.  
    3. var widgetFactory = Substitute.For<IWidgetFactory>(); 
    4. var subject = new Sprocket(widgetFactory); 
    5.  
    6. // OK: Use arg matcher for a return value: 
    7. widgetFactory.Make(Arg.Is<int>(x => x > 10)).Returns(TestWidget); 
    8.  
    9. /* ACT */ 
    10.  
    11. // NOT OK: arg matcher used with a real call: 
    12. // subject.StartWithWidget(Arg.Any<int>()); 
    13.  
    14. // Use a real argument instead: 
    15. subject.StartWithWidget(4); 
    16.  
    17. /* ASSERT */ 
    18.  
    19. // OK: Use arg matcher to check a call was received: 
    20. widgetFactory.Received().Make(Arg.Is<int>(x => x > 0)); 

    回调,空调用

    1. var counter = 0
    2. calculator 
    3. .Add(0,0
    4. .ReturnsForAnyArgs(x => 0
    5. .AndDoes(x => counter++); 
    6.  
    7. calculator.Add(7,3); 
    8. calculator.Add(2,2); 
    9. calculator.Add(11,-3); 
    10. Assert.AreEqual(counter, 3); 

    when...do...

    1. public interface IFoo
    2. void SayHello(string to)

    3. [Test] 
    4. public void SayHello()
    5. var counter = 0
    6. var foo = Substitute.For<IFoo>(); 
    7. foo.When(x => x.SayHello("World")) 
    8. .Do(x => counter++); 
    9.  
    10. foo.SayHello("World"); 
    11. foo.SayHello("World"); 
    12. Assert.AreEqual(2, counter); 

    复杂调用

    1. var sub = Substitute.For<ISomething>(); 
    2.  
    3. var calls = new List<string>(); 
    4. var counter = 0
    5.  
    6. sub 
    7. .When(x => x.Something()) 
    8. .Do( 
    9. Callback.First(x => calls.Add("1")) 
    10. .Then(x => calls.Add("2")) 
    11. .Then(x => calls.Add("3")) 
    12. .ThenKeepDoing(x => calls.Add("+")) 
    13. .AndAlways(x => counter++) 
    14. ); 
    15.  
    16. for (int i = 0; i < 5; i++) 

    17. sub.Something(); 

    18. Assert.That(String.Concat(calls), Is.EqualTo("123++")); 
    19. Assert.That(counter, Is.EqualTo(5)); 

    抛出异常

    1. //For non-voids: 
    2. calculator.Add(-1, -1).Returns(x => { throw new Exception(); }); 
    3.  
    4. //For voids and non-voids: 
    5. calculator 
    6. .When(x => x.Add(-2, -2)) 
    7. .Do(x => { throw new Exception(); }); 
    8.  
    9. //Both calls will now throw. 
    10. Assert.Throws<Exception>(() => calculator.Add(-1, -1)); 
    11. Assert.Throws<Exception>(() => calculator.Add(-2, -2)); 

    事件

    1. public interface IEngine
    2. event EventHandler Idling; 
    3. event EventHandler<LowFuelWarningEventArgs> LowFuelWarning; 
    4. event Action<int> RevvedAt; 

    5.  
    6. public class LowFuelWarningEventArgs : EventArgs
    7. public int PercentLeft { get; private set; } 
    8. public LowFuelWarningEventArgs(int percentLeft)
    9. PercentLeft = percentLeft; 


    1. var wasCalled = false
    2. //设置事件 
    3. engine.Idling += (sender, args) => wasCalled = true
    4. //执行事件 
    5. //Tell the substitute to raise the event with a sender and EventArgs: 
    6. engine.Idling += Raise.EventWith(new object(), new EventArgs()); 
    7.  
    8. Assert.True(wasCalled); 

    事件参数

    1. engine.LowFuelWarning += (sender, args) => numberOfEvents++; 
    2. //Raise.EventWith<TEventArgs>(...) 
    3. //Raise event with specific args, any sender: 
    4. engine.LowFuelWarning += Raise.EventWith(new LowFuelWarningEventArgs(10)); 
    5. //Raise event with specific args and sender: 
    6. engine.LowFuelWarning += Raise.EventWith(new object(), new LowFuelWarningEventArgs(10)); 
    7.  
    8. Assert.AreEqual(2, numberOfEvents); 

    代理事件

    1. var sub = Substitute.For<INotifyPropertyChanged>(); 
    2. bool wasCalled = false
    3. sub.PropertyChanged += (sender, args) => wasCalled = true
    4.  
    5. sub.PropertyChanged += Raise.Event<PropertyChangedEventHandler>(this, new PropertyChangedEventArgs("test")); 
    6.  
    7. Assert.That(wasCalled); 

    action事件

    1. int revvedAt = 0;; 
    2. engine.RevvedAt += rpm => revvedAt = rpm; 
    3.  
    4. engine.RevvedAt += Raise.Event<Action<int>>(123); 
    5.  
    6. Assert.AreEqual(123, revvedAt); 

    自动递归模拟

    递归模拟

    1. public interface INumberParser
    2. IEnumerable<int> Parse(string expression)

    3. public interface INumberParserFactory
    4. INumberParser Create(char delimiter)

    1. var factory = Substitute.For<INumberParserFactory>(); 
    2. var parser = Substitute.For<INumberParser>(); 
    3. factory.Create(',').Returns(parser); 
    4. parser.Parse("an expression").Returns(new[] {1,2,3}) 
    5. Assert.AreEqual( 
    6. factory.Create(',').Parse("an expression"), 
    7. new[] {1,2,3}); 
    8.  
    9. //or 
    10. var factory = Substitute.For<INumberParserFactory>(); 
    11. factory.Create(',').Parse("an expression").Returns(new[] {1,2,3}); 
    12. Assert.AreEqual( 
    13. factory.Create(',').Parse("an expression"), 
    14. new[] {1,2,3}); 
    15.  
    16.  
    17. var firstCall = factory.Create(','); 
    18. var secondCall = factory.Create(','); 
    19. var thirdCallWithDiffArg = factory.Create('x'); 
    20.  
    21. Assert.AreSame(firstCall, secondCall); 
    22. Assert.AreNotSame(firstCall, thirdCallWithDiffArg); 

    Substitute chains(链)

    1. public interface IContext
    2. IRequest CurrentRequest { get; } 

    3. public interface IRequest
    4. IIdentity Identity { get; } 
    5. IIdentity NewIdentity(string name)

    6. public interface IIdentity {  
    7. string Name { get; }  
    8. string[] Roles(); 

    1. var context = Substitute.For<IContext>(); 
    2. context.CurrentRequest.Identity.Name.Returns("My pet fish Eric"); 
    3. Assert.AreEqual( 
    4. "My pet fish Eric",  
    5. context.CurrentRequest.Identity.Name); 

    自动值

    1. var identity = Substitute.For<IIdentity>(); 
    2. Assert.AreEqual(String.Empty, identity.Name); 
    3. Assert.AreEqual(0, identity.Roles().Length); 

    设置out或者ref参数

    1. public interface ILookup
    2. bool TryLookup(string key, out string value)

    1. //Arrange 
    2. var value = ""
    3. var lookup = Substitute.For<ILookup>(); 
    4. lookup 
    5. .TryLookup("hello", out value
    6. .Returns(x => {  
    7. x[1] = "world!"
    8. return true
    9. }); 
    10.  
    11. //Act 
    12. var result = lookup.TryLookup("hello", out value); 
    13.  
    14. //Assert 
    15. Assert.True(result); 
    16. Assert.AreEqual(value, "world!"); 

    行为和参数匹配

    执行回调

    1. public interface IOrderProcessor
    2. void ProcessOrder(int orderId, Action<bool> orderProcessed)

    3.  
    4. public class OrderPlacedCommand
    5. IOrderProcessor orderProcessor; 
    6. IEvents events; 
    7. public OrderPlacedCommand(IOrderProcessor orderProcessor, IEvents events)
    8. this.orderProcessor = orderProcessor; 
    9. this.events = events; 

    10. public void Execute(ICart cart)
    11. orderProcessor.ProcessOrder( 
    12. cart.OrderId,  
    13. wasOk => { if (wasOk) events.RaiseOrderProcessed(cart.OrderId); } 
    14. ); 


    1. [Test] 
    2. public void Placing_order_should_raise_order_processed_when_processing_is_successful()
    3. //Arrange 
    4. var cart = Substitute.For<ICart>(); 
    5. var events = Substitute.For<IEvents>(); 
    6. var processor = Substitute.For<IOrderProcessor>(); 
    7. cart.OrderId = 3
    8. //Arrange for processor to invoke the callback arg with `true` whenever processing order id 3 
    9. processor.ProcessOrder(3, Arg.Invoke(true)); 
    10.  
    11. //Act 
    12. var command = new OrderPlacedCommand(processor, events); 
    13. command.Execute(cart); 
    14.  
    15. //Assert 
    16. events.Received().RaiseOrderProcessed(3); 

    用参数执行操作

    1. var argumentUsed = 0
    2. calculator.Multiply(Arg.Any<int>(), Arg.Do<int>(x => argumentUsed = x)); 
    3.  
    4. calculator.Multiply(123, 42); 
    5.  
    6. Assert.AreEqual(42, argumentUsed); 
    1. var firstArgsBeingMultiplied = new List<int>(); 
    2. calculator.Multiply(Arg.Do<int>(x => firstArgsBeingMultiplied.Add(x)), 10); 
    3.  
    4. calculator.Multiply(2, 10); 
    5. calculator.Multiply(5, 10); 
    6. calculator.Multiply(7, 4567); //Will not match our Arg.Do as second arg is not 10 
    7.  
    8. Assert.AreEqual(firstArgsBeingMultiplied, new[] { 2, 5 }); 

    参数规范

    1. var numberOfCallsWhereFirstArgIsLessThan0 = 0
    2. //Specify a call where the first arg is less than 0, and the second is any int. 
    3. //When this specification is met we'll increment a counter in the Arg.Do action for  
    4. //the second argument that was used for the call, and we'll also make it return 123. 
    5. calculator 
    6. .Multiply( 
    7. Arg.Is<int>(x => x < 0),  
    8. Arg.Do<int>(x => numberOfCallsWhereFirstArgIsLessThan0++) 
    9. ).Returns(123); 
    10.  
    11. var results = new[] { 
    12. calculator.Multiply(-4, 3), 
    13. calculator.Multiply(-27, 88), 
    14. calculator.Multiply(-7, 8), 
    15. calculator.Multiply(123, 2) //First arg greater than 0, so spec won't be met. 
    16. }; 
    17.  
    18. Assert.AreEqual(3, numberOfCallsWhereFirstArgIsLessThan0); //3 of 4 calls have first arg < 0 
    19. Assert.AreEqual(results, new[] {123, 123, 123, 0}); //Last call returns 0, not 123 

    检查调用命令

    1. [Test] 
    2. public void TestCommandRunWhileConnectionIsOpen()
    3. var connection = Substitute.For<IConnection>(); 
    4. var command = Substitute.For<ICommand>(); 
    5. var subject = new Controller(connection, command); 
    6.  
    7. subject.DoStuff(); 
    8.  
    9. Received.InOrder(() => { 
    10. connection.Open(); 
    11. command.Run(connection); 
    12. connection.Close(); 
    13. }); 

    1. [Test] 
    2. public void SubscribeToEventBeforeOpeningConnection()
    3. var connection = Substitute.For<IConnection>(); 
    4. connection.SomethingHappened += () => { /* some event handler */ }; 
    5. connection.Open(); 
    6.  
    7. Received.InOrder(() => { 
    8. connection.SomethingHappened += Arg.Any<Action>(); 
    9. connection.Open(); 
    10. }); 

  • 相关阅读:
    Java的mybatis随笔
    通过字节输入输出流,对标识文件读写,并按规定输出
    Java中异常的处理以及自定义异常,抛出异常到方法调用栈底层
    Java接口实现传参
    类的高级概念
    Java面向对象特征之封装
    Java中的方法(形参及实参)return返回类型
    Java中的数组添加,数组相关代码
    并发思考-actor和thread那个好点?
    TensorFlow实现线性回归模型代码
  • 原文地址:https://www.cnblogs.com/mmry/p/7216340.html
Copyright © 2020-2023  润新知