今天的文章主要参考於 NSubstitute官方网站,正所谓工欲善其事,必先利其器,我们若想要透过 NSub 自动化写出好的假物件,那就要先了解 NSub(就跟在使用 NUnit3 就要了解它常用的特性 SetUp 等等语法一样,详情可见 Day-6、Day-7)。
所以,接下来会介绍几个比较常见的语法:建置 Substitute、Return()、Received()、Arg.Any()、Arg.Is(T value),而今天的商业逻辑主角就是官方网站提供的计算机方法,分别有模式 Mode 属性与 Add 方法,程序码如下:
namespace CalculatorLibrary
{
public interface ICalculator
{
string Mode { get; set; }
int Add(int a, int b);
}
}
在 NSubstitute 中,最一开始我们要利用 NSub 建置假物件,而建置假物件的基本语法如下:
var substitute = Substitute.For<ISomeInterface>();
因此,若要建置我们上面提到的计算机假物件,则测试码如下:
var calculator = Substitute.For<ICalculator>();
Substitute 除了基本的假物件建置外,也可以有建构子、复数个介面产制相对应及委派的写法,范例如下:
// 带有建构子
var substitute = Substitute.For<SomeClassWithCtorArgs>(5, "hello world");
// 复数个介面
var substitute = Substitute.For<IInterface1, IInterface2>();
// 委派
var substitute = Substitute.For<Func<string>>();
Return 方法,顾名思义就是指新增回传的方法,我们在设立假物件的时候,为了让商业逻辑能顺利运作,通常会给定我们预期的值,在 Day-9 ~ Day-14 的时候,花了六天的时候帮各种假物件刻写各种预期结果,而在 NSub 之後,可以利用 Return 来预期我们要的值,范例如下:
[Test]
public void DemoReturnTest()
{
// Arrange
var calculator = Substitute.For<ICalculator>();
calculator.Add(1, 2).Returns(3);
// Act + Assert
Assert.AreEqual(calculator.Add(1, 2), 3);
}
可以看到我们把 calculator 里面的 Add,预设呼叫 Add(1, 2) 的时候要回传数值 3。
当然,我们可以写复数个 Return 结果,如下:
[Test]
public void DemoReturnTest2()
{
// Arrange
var calculator = Substitute.For<ICalculator>();
calculator.Mode.Returns("HEX", "DEC", "BIN");
// Act + Assert
Assert.AreEqual(calculator.Mode, "HEX");
Assert.AreEqual(calculator.Mode, "DEC");
Assert.AreEqual(calculator.Mode, "BIN");
}
Received 方法,从字面上解读是接受到了什麽东西,那在 NSub 看到这个词所代表在执行测试时,该测试总共执行了多少次该方法;换言之,我们可以去确认有没有执行该方法(模拟物件的好帮手),执行了多少次,来看这段范例:
[Test]
public void DemoReceivedTest()
{
// Arrange
var calculator = Substitute.For<ICalculator>();
calculator.Add(1, 2).Returns(3);
// Act
calculator.Add(1, 2);
calculator.Add(1, 2);
// Assert
calculator.Received().Add(1, 2);
// calculator.Received(2).Add(1, 2);
// calculator.Received(4).Add(1, 2);
}
可以看到最後 Assert 阶段,我们来确认是否有执行 Add 方法(Assert 第一行),再进阶一点则是验证执行几次(如 Assert 第二行与第三行)。顺带一提,若执行第三行的时候,会发生失败(因为在 Act 阶段总共只执行了两次;但在验证就说需要四次,两边不符,Visual Studio 会跳出以下的错误讯息。)
Arg.Any() 是可协助我们输入任何的参数,很多时候在呼叫第三方套件会需要设定一些参数,但对於商业逻辑的撰写其实并没有直接影响的时候,就可以利用 Arg.Any() 帮助我们忽略对这些参数的设定,那示范的程序码如下:
[Test]
public void DemoArgAnyTest()
{
// Arrange
var calculator = Substitute.For<ICalculator>();
// Act
calculator.Add(10, -5);
// Assert
calculator.Received().Add(10, Arg.Any<int>());
}
从该段程序码可以看出,我们只在意在执行 Add 方法的时候,第一个参数有代入 10,而第二个参数是什麽,其实不是这次测试的关注点,仅只要符合介面要输入的参数即可。
除了写在验证上,我们也可以在 Act 阶段使用,如下:
[Test]
public void DemoArgAnyTest2()
{
// Arrange
var calculator = Substitute.For<ICalculator>();
calculator.Add(Arg.Any<int>(), Arg.Any<int>()).Returns(x => (int)x[0] + (int)x[1]);
// Act + Assert
Assert.AreEqual(calculator.Add(5, 10), 15);
}
但倘若我们要对参数要带有设定的话,NSub 也有提供相对应的方法 —— Arg.Is(T value),其中,通常後面的 T value 会有两种呈现方式,给定值或利用 Lambda 语法带出 T value 的条件,直接看测试码,如下:
[Test]
public void DemoArgIsTest1()
{
// Arrange
var calculator = Substitute.For<ICalculator>();
// Act
calculator.Add(10, -5);
// Assert
calculator.Received().Add(10, Arg.Is(-5));
}
[Test]
public void DemoArgIsTest2()
{
// Arrange
var calculator = Substitute.For<ICalculator>();
// Act
calculator.Add(10, -5);
// Assert
calculator.Received().Add(10, Arg.Is<int>(x => x < 0));
}
今天要来用 Template Driven Forms 的方式实作一个很简易的动态表单,使用上有点...
前言 我们已经学会使用长条图来做资料探索。然而,Tableau Desktop 除了长条图外,还有其...
假使设定HTML: <div class="container"> ...
Method程序设计中,可以说是将程序模组化,这样有助於加速程序的开发、便於分析与维护等,如果要重复...
前述 今天因为时间不足 T_T .... 所以教大家使用 qrcode.react ,可以很快速的产...