Day 17-隔离框架 (isolation Framework) - NSubstitute 基本介绍-2 (核心技术-9)

NSubstitute 基本语法前言

今天的文章主要参考於 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 基本语法-1:建置 Substitute

在 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>>();

NSubstitute 基本语法-2:Return()

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");
}

NSubstitute 基本语法-3:Received()

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 会跳出以下的错误讯息。)

https://ithelp.ithome.com.tw/upload/images/20210917/20127378jvmZbgJ1s4.png


NSubstitute 基本语法-4:Arg.Any()

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);
}

NSubstitute 基本语法-5:Arg.Is(T value)

但倘若我们要对参数要带有设定的话,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));
}

<<:  [DAY 02]环境建置 : 组出你的环境--前导

>>:  Day-02 JavaScript资料型别(1)

Angular 深入浅出三十天:表单与测试 Day10 - Template Driven Forms 实作 - 动态表单初体验

今天要来用 Template Driven Forms 的方式实作一个很简易的动态表单,使用上有点...

[Day15] Tableau 轻松学 - 地图工作表

前言 我们已经学会使用长条图来做资料探索。然而,Tableau Desktop 除了长条图外,还有其...

Grid笔记

假使设定HTML: <div class="container"> ...

Day 19 Method

Method程序设计中,可以说是将程序模组化,这样有助於加速程序的开发、便於分析与维护等,如果要重复...

Day 19 - 建立 canvas QRCode

前述 今天因为时间不足 T_T .... 所以教大家使用 qrcode.react ,可以很快速的产...