iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0
Software Development

單元測試從入門到進階之路 (以 C# NUnit 3 X NSubstitute 為例)系列 第 17

Day 17-隔離框架 (isolation Framework) - NSubstitute 基本介紹-2 (核心技術-9)

  • 分享至 

  • xImage
  •  

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 16-隔離框架 (isolation Framework) - NSubstitute 基本介紹 (核心技術-8)
下一篇
Day 18-隔離框架 (isolation Framework) - NSubstitute 基本介紹-3 (核心技術-10)
系列文
單元測試從入門到進階之路 (以 C# NUnit 3 X NSubstitute 為例)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言