Day 7-单元测试 NUnit 更多常用的特性-2 (基础-6)

如何撰写测试验证例外 — ExpectedExcetption 与 Assert.Throws(delegate)

我们在撰写商业逻辑时,能够准确预期功能在什麽情况会产生例外也是一门学问;因此,在此段会探讨验证例外的写法与历史(来源可参考单元测试的艺术 2.6.2 节或 Marcus 文章的 NUnit 测试例外 Exception)。

在探讨验证例外之前,我们先再回顾 HelloBank 这只商业逻辑专案的内容—存款功能,如下:

public void Add(double amount)
{
    if (amount < 0)
    {
        throw new ArgumentOutOfRangeException(nameof(amount));
    }

    balance += amount;
}

从此段程序码,可以看出来当使用者存款的金额小於 0 元的时候,会发生 ArgumentOutOfRangeException。而在早期 NUnit 2 的时代,是采用一种写法叫 [ExpectedExcetption] 的写法,如下:

[Test]
[ExpectedExcetption(typeof(ArgumentOutOfRangeException))]
public void Adding_Negative_Funds_Throws()
{
    // Act
    account.Add(-500);
}

但在单元测试的艺术有提到该方法并非良好的方法,其原因为 [ExpectedExcetption] 的概念是告诉测试执行器,将这个功能放进 try-catch 的区块中,找出该段程序码的 Exception。这样的风险可能会造成抓取出来的例外可能不是我们预期的例外(比如建构函式写错,抛出例外时造成测试未成功,进而导致误判程序码出错原因)。另外,NUnit 3 已将此写法删除(换言之,这种写法已经走入历史了)。

在单元测试的艺术提供的写法是利用 Assert.Catch(delegate),该方法会回传例外的物件执行个体,进而对该物体验证其正确性(比如抓取其中的 Message,并验证是否有涵盖我们预期的字串)。但在 NUnit 3 有提供另一种写法,可以更简洁地解决验证例外,程序码如下:

[Test]
public void Adding_Negative_Funds_Throws()
{
    // Act + Assert
    Assert.Throws<ArgumentOutOfRangeException>(() => account.Add(-500));
}

程序码采用 Assert.Throws(delegate) 写法,我们把原先 Act 的动作利用 Lambda 语法写进委派中,所以可看到 Act 与 Assert 的程序码写在同一行,利用 Assert.Throws 验证 Lambda 内的委派结果与泛型是同一种例外类别。

PS:若对 C# 不懂,T 是指泛型,而 delegate 是指委派(在此不解释各自的细节,可参考能不能讲一下什麽是泛型(Generics)老宅笔记本: .NET委派(delegate),写得满浅显易懂的)。


单元测试的分类 — Category

该特性如标题,顾名思义就是指把测试指定你分类的名称,程序码如下:

[Test]
[Category("Exception Tests")]
public void Adding_Negative_Funds_Throws()
{
    // Act + Assert
    Assert.Throws<ArgumentOutOfRangeException>(() => account.Add(-500));
}

而透过 Windows Test Explorer 可看到做分类的特性,如图:

https://ithelp.ithome.com.tw/upload/images/20210907/201273781evWdZTiiU.png

PS:尚未在 Visual Studio for Mac 看到相关的 UI 可以显性特性(也可能是我没找到),以及如何透过 Category 只跑相对应的测试,也会在之後花时间 Study 并补齐。


<<:  [Day 2] 总而言之把前置作业全解决

>>:  GitHub Branch 策略 - 哪一种方式适合你?

Day-2 Excel出现#字号!难道是中毒了吗!?

你是不是常常在编辑试算表时遇到”####”呢?别紧张,其实出现这个符号并不是你输入错误喔,而是你的栏...

005-元件名称_2

关於上篇提到的元件,对我而言,属於在讨论阶段,会比较经常拿出来讨论的元件。真正在实作以及管理画面时,...

服务自动化中提高效率真的好吗?

这次做的微型仓储系统的时候,初期系统是以单电梯设计的,後来爲了提高效率,改成了双电梯; 这就像是有一...

Day 7 ( 入门 ) 按钮控制猫咪 ( 广播 )

按钮控制猫咪 ( 广播 ) 教学原文参考:按钮控制猫咪 ( 广播 ) 这篇文章会介绍,如何在 Scr...

30天学会C语言: Day 8-无限执行篇

指派/指定 运算子(Assignment Operator) 可以用来设定变数值的运算子,前面用过的...