手记

NSubstitute入门基础

最简单的入门方式就是创建一个测试项目,并将 NSubstitute 引用到其中。可以通过 NuGet 或 OpenWrap 来获取 NSubstitute 包。也可以直接下载 NSubstitute 文件,然后将 NSubstitute.dll 引用到项目中。

然后就可以创建一个新的测试 Fixture(可以选择使用你最喜欢的UT测试框架,本文涉及的示例中我们使用MSTest),开始思考从哪里入手。

首先,添加 using NSubstitute; 到当前的C#代码文件中,有了它我们就可以开始创建替身了。

现在,比如我们有一个非常简单的计算器接口:

1     public interface ICalculator2     {3       int Add(int a, int b);4       string Mode { get; set; }5       event EventHandler PoweringUp;6     }

我们可以让NSubstitute来创建类型实例的替代实例。可以创建诸如 Stub、Mock、Fake、Spy、Test Double 等,但当我们只是想要一个能有一定程度控制的替代实例时,为什么我们要困扰于此呢?

1     [TestMethod]2     public void Test_GetStarted_GetSubstitute()3     {4       ICalculator calculator = Substitute.For<ICalculator>();5     }

现在,我们可以告诉被创建的替代实例,当方法被调用时返回一个值:


1     [TestMethod]2     public void Test_GetStarted_ReturnSpecifiedValue()3     {4       ICalculator calculator = Substitute.For<ICalculator>();5       calculator.Add(1, 2).Returns(3);6 7       int actual = calculator.Add(1, 2);8       Assert.AreEqual<int>(3, actual);9     }


我们可以检查该替代实例是否接收到了一个指定的调用,或者未收到某指定调用:


1     [TestMethod]2     public void Test_GetStarted_ReceivedSpecificCall()3     {4       ICalculator calculator = Substitute.For<ICalculator>();5       calculator.Add(1, 2);6 7       calculator.Received().Add(1, 2);8       calculator.DidNotReceive().Add(5, 7);9     }


如果 Received() 断言失败,NSubstitute 会尝试给出有可能是什么问题:


1     [TestMethod]2     [ExpectedException(typeof(ReceivedCallsException))]3     public void Test_GetStarted_DidNotReceivedSpecificCall()4     {5       ICalculator calculator = Substitute.For<ICalculator>();6       calculator.Add(5, 7);7 8       calculator.Received().Add(1, 2);9     }


Expected to receive a call matching:
    Add(1, 2)
Actually received no matching calls.
Received 1 non-matching call (non-matching arguments indicated with '*' characters):
    Add(*5*, *7*)

我们也可以对属性使用与方法类似的 Retures() 语法,或者继续使用简单的属性 setter 来设置返回值。


 1     [TestMethod] 2     public void Test_GetStarted_SetPropertyValue() 3     { 4       ICalculator calculator = Substitute.For<ICalculator>(); 5  6       calculator.Mode.Returns("DEC"); 7       Assert.AreEqual<string>("DEC", calculator.Mode); 8  9       calculator.Mode = "HEX";10       Assert.AreEqual<string>("HEX", calculator.Mode);11     }


NSubstitute 支持参数匹配功能,可以设置参数规则,并断言判断是否接收到参数匹配的调用。


 1     [TestMethod] 2     public void Test_GetStarted_MatchArguments() 3     { 4       ICalculator calculator = Substitute.For<ICalculator>(); 5  6       calculator.Add(10, -5); 7  8       calculator.Received().Add(10, Arg.Any<int>()); 9       calculator.Received().Add(10, Arg.Is<int>(x => x < 0));10     }


我们也可以在使用参数匹配功能的同时,传递一个函数给 Returns() ,以此来使替代实例具有更多的功能。


 1     [TestMethod] 2     public void Test_GetStarted_PassFuncToReturns() 3     { 4       ICalculator calculator = Substitute.For<ICalculator>(); 5       calculator 6          .Add(Arg.Any<int>(), Arg.Any<int>()) 7          .Returns(x => (int)x[0] + (int)x[1]); 8  9       int actual = calculator.Add(5, 10);10 11       Assert.AreEqual<int>(15, actual);12     }


Returns() 也可通过构造一个返回值序列来指定多个参数。


 1     [TestMethod] 2     public void Test_GetStarted_MultipleValues() 3     { 4       ICalculator calculator = Substitute.For<ICalculator>(); 5       calculator.Mode.Returns("HEX", "DEC", "BIN"); 6  7       Assert.AreEqual<string>("HEX", calculator.Mode); 8       Assert.AreEqual<string>("DEC", calculator.Mode); 9       Assert.AreEqual<string>("BIN", calculator.Mode);10     }

最后,我们可以在替代实例上引发事件通知:

 1     [TestMethod] 2     public void Test_GetStarted_RaiseEvents() 3     { 4       ICalculator calculator = Substitute.For<ICalculator>(); 5       bool eventWasRaised = false; 6  7       calculator.PoweringUp += (sender, args) => 8       { 9         eventWasRaised = true;10       };11 12       calculator.PoweringUp += Raise.Event();13 14       Assert.IsTrue(eventWasRaised);15     }

基本上这些就是入门 NSubstitute 的全部内容。

0人推荐
随时随地看视频
慕课网APP