Day 9-假物件 (Fake) - 虚设常式 (Stub)-1 (核心技术-1)

虚设常式(Stub)简介

今天的文章进入了新的系列,那因为接下来的概念是非常抽象的,所以会介绍数个核心技术的概念,接着探讨如何使用。与前一系列最大的差别在於我们所撰写的商业逻辑系统的方法开始有外部引用的情况,比如:Web 服务、系统时间、执行绪或其他类似的第三方套件。

而单元测试的艺术提到这个关键点在於:在你的测试中你无法决定相依物件的回传值,也无法控制他的行为(例如你想模拟他将抛出一个例外)。此时,就是假物件(Fake)该介入的时机了,假物件又分虚设常式(Stub)与模拟物件(Mock),而我们先介绍虚设常式。在单元测试的艺术中,是这样定义虚设常式:

是在系统中产生一个可控的替代物件,来取代一个外部相依物件。

我相信许多人看到上述的定义,应该会一头雾水(当时我看到这段也觉得好抽象),那麽接下来会用故事搭配撰写程序码的手法来说明虚设常式。/images/emoticon/emoticon08.gif


看程序码说故事 (Stub-1)

今天有个开发者,听到指示说要写一只 E-mail 通知系统,在法呼叫这只方法时,就会发起 E-mail,并且在寄完後要回传寄送情况(预设为一串字串),於是这位开发者就写了如下的程序码:

using JJEmail;

public class EmailSystem
{
    public EmailSystem()
    {

    }

    public string EmailFunction(string mailAddress, string mailMessage)
    {
        var EmailService = new JJEmailService();
        var SendResult = EmailService.SendEmail(Address, Message);

        return SendResult;
    }
}

这个开发者很开心的引用 JJEmail 解决需求上的问题,并在 Code Review 阶段提供程序码,而测试工程师以测试的观点说明了这只方法目前的窘境,如下:

using NUnit.Framework;

[TestFixture]
public class EmailSystemUnitTests
{
    [Test]
    public void EmailFunctionTest()
    {
        // Arrange
        var TestEmailSystem = new EmailSystem();
        
        // Act
        var TestResult = TestEmailSystem
                        .EmailFunction("[email protected]", "Test Demo");

        // Assert
        Assert.AreEqual(TestResult, "Success");
    }
}

从程序码看出问题点

上述的程序码出现了两个问题点:

(1) 从测试程序中,可以看出在 Act 阶段,呼叫了 EmailFunction 方法,而回看原始码也的确有 EmailFunction 的流程;但是今天假设这个 JJEmail 的内部程序码有出错,会导致预期的结果永远出不来(比如他们官方的文件写会回传 Success,但他们套件的开发人员却写成 success)。而大多时候 C# 引用的第三方套件是已经编译好的 .dll 档案,所以很难更动里面的原始码;於是乎,这只测试就是被 JJEmail 套件绑架的测试,不符合优秀测试所提到的要百分百掌控的精神。

(2) 此外,这只方法已经与 E-mail 套件产生了耦合,对而後扩充与维护不利。而从测试的观点,假设今天要导入假物件(虚设常式或模拟物件),会找不到适合的切入点(在测试的术语叫接缝,Seam)替换掉第三方套件。因此,导入 OOP 的精神可使程序码解耦,并且对系统有具有较高的弹性,这也是为什麽在讨论测试时,也会一并讨论目前的设计模式,因应不同的设计模式会有不同的测试切入与手法。

那明天,会说明如何把上面所述的状况拆解,让测试开发好并找切入点撰写测试。


<<:  部署 Google App Script 专案(2) & Line Bot 简单回应讯息

>>:  [序章] 自然语言处理初探

全端入门Day18_前端程序撰写之CSS终

昨天介绍了些F12的功能,今天要来说CSS的框架。 CSS的框架:Bootstrap 因为我目前碰的...

007 2021线上看

007 2021线上看 世界局势波诡云谲,再度出山的邦德(丹尼尔·克雷格饰)面临有史以来空前的危机。...

Day 21:总汇复习-Vuex、Route

前几篇介绍了 Vuex 管理资料状态,以及在生命周期或导航守卫发送 API 的时机点,再次回到专案范...

Day8 - 如何读取委托回报、成交回报

你还在看,真有心,来吧! 我们一起牵手向前行! 读取委托回报,通常下单(raplace order)...

Day-21 队列(Queue)与循环对列(Circular Queue)

队列(queue)介绍 队列就如同堆叠一般,是一种线性表,与堆叠不同的地方在於,堆叠的push和po...