Day 26-Unit Test 应用於 Async Code-2 (情境及应用-6)

Unit Test 应用於 Async Code-2 - 用程序码讲故事(测试码 Exception 篇章)

那今天的内容是延续昨天的商业逻辑所撰写的测试码,那接下来要探讨的议题是当 Load 方法要注入 Exception 的情境时,针对非同步处理要如何撰写,那在 NUnit3 的套件中有提供一个方法叫 Assert.ThrowsAsync,那其方法是类似於 Assert.Throws,应用於非同步的情境,测试码如下:

[Test]
public void FailedGet_Ver1()
{
    // Arrange
    var storage = Substitute.For<IStorage>();

    storage.Load("key").Throws<TimeoutException>();

    var cache = new DemoCache(storage);

    // Act + Assert
    Assert.ThrowsAsync<TimeoutException>(async () => await cache.Get("key"));
}

从这边我们可以看到,若使用 Assert.ThrowsAsync 的语法,在 Lambda 结构里就会去执行非同步处理;因此,从 Lambda 中就会取得相对应的值(范例为 string),所以在宣告的时候并不是用 async Task<string>,而是 void 方法。但倘若我们还要验证共执行几次,如下:

[Test]
public async Task FailedGet_Ver2()
{
    // Arrange
    var storage = Substitute.For<IStorage>();

    storage.Load("key").Throws<TimeoutException>();

    var cache = new DemoCache(storage);

    // Act + Assert
    Assert.ThrowsAsync<TimeoutException>(async () => await cache.Get("key"));

    await storage.Received(1).Load("key");
}

因 Received() 需要等 cache.Get 执行完,因此就需要使用非同步语法。


Unit Test 应用於 Async Code-3 - 用程序码讲故事(测试码 Reload 篇章)

接下来要探讨当 Returns 含有 Multiple Values 的时候,在搭配 Reload 的概念,把 Cache 里面的东西从 Storage 取出,每当执行 Load 的概念时,则会往後取一个数值,若已到最後一个时,则会固定在该数值,测试马如下:

[Test]
public async Task SingleGet_WithReload()
{
    // Round 1
    // Arrange
    var storage = Substitute.For<IStorage>();

    storage.Load("key").Returns("value1", "value2", "value3");

    var cache = new DemoCache(storage);

    // Act
    var result1 = await cache.Get("key");
    var result2 = await cache.Get("key");

    // Assert
    Assert.AreEqual(result1, "value1");
    Assert.AreEqual(result2, "value1");

    // Round 2
    // Act
    var result3 = await cache.Get("key");

    // Assert
    Assert.AreEqual(result3, "value2");

    // Round 3
    // Act
    var result4 = await cache.Get("key");
    var result5 = await cache.Get("key");
    
    // Assert
    Assert.AreEqual(result4, "value3");
    Assert.AreEqual(result5, "value3");
    
    // Round 4
    // Act
    var result6 = await cache.Get("key");
    var result7 = await cache.Get("key");
    
    // Assert
    Assert.AreEqual(result6, "value3");
    Assert.AreEqual(result7, "value3");
}

原参考来源是只测试两次,那为了示意每 Reload 会往後延一个以及固定在最後一个数值;因此,这边测试码写了 Reload 4 Round,并且在 Round 3 就已到第三个数值,Round 4 依旧在第三个数值。而最後的测试码是测试当有多个非同步执行的时候,两边执行的次数是否符合预期,测试码如下:

[Test]
public async Task MultipleGets_WithReload()
{
    // Arrange
    var storage = Substitute.For<IStorage>();

    var cache = new DemoCache(storage);

    // Act
    await cache.Get("key1");
    await cache.Get("key1");
    await cache.Get("key2");
    await cache.Get("key1");
    await cache.Get("key2");
    await cache.Get("key2");
    await cache.Get("key2");
    await cache.Get("key2");

    // Assert
    await storage.Received(2).Load("key1");
    await storage.Received(3).Load("key2");
}

Unit Test 应用於 Async Code - 结尾

从这两天的范例可以看出测试码验证非同步处理与商业逻辑一样,都是要采用 Task、async 与 await 语法;但如果把 Act 的方法直接写在 Assert 的 Lambda 方法中,则宣告的时候则直接采用 void 即可(如 Exception 篇章),以及探讨 Returns 的用码。


<<:  Python 练习

>>:  【後转前要多久】# Day11 CSS - 区块元素、行内元素

[Day4] Flutter - 水平布局容器 ( Row )

前言 Hi, 我是鱼板伯爵今天要教大家 Row 这个容器,教学内容只会撷取片段程序码,建议大家搭配完...

Re: 新手让网页 act 起来: Day02 - 永远的起点 Hello world!

在开始使用 React 之前,先来回想一下刚学习原生 JS 的时候,我们是怎麽在页面产生 DOM N...

[Day29]- 新手的Web系列JSON Injection 0x2

Day29- 新手的Web系列JSON Injection 0x2 正文 web2.0导入了很多Aj...

抽象类别与介面 (1)

在上一篇文章中提到,我们可以将不同类别当中的共同属性或方法,提取出来放在 parent 类别当中,然...

专案是实现使命、愿景,及战略的具体努力!

分享一些多年来专案管理及工作的心得: 专案是实现使命、愿景,及战略的具体努力。使命感、远见与作梦的能...