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

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

前景提要,昨天提到开发者要开发 Email 通知系统,於是他就利用 JJEmail 套件里面的 SendEmail 方法解决 Email 通知系统里面的寄信功能,并回传寄信的情况(资料型别为一串字串);但在 Code Review 阶段被质疑说测试出现问题时,无法判别结果失败是因为程序码撰写有误,还是因为套件出错,此外,测试找不到适当的切入点撰写假物件。

因此,今天要先解决商业逻辑程序码透过依赖反转的概念,设计介面并让 JJEmail 用依赖注入的方式写进逻辑,以下为目前的流程图:

https://ithelp.ithome.com.tw/upload/images/20210912/20127378lfRw1jjKS2.png


在单元测试的艺术中曾提到一个让测试介入更简单的观点:任何物件导向的问题,都可以透过增加一个中介层(a layer of indirection)来解决;当然,除了中介层过多的这个问题;换言之,从 C# 的角度看这段话,一个简单又好用的做法就是在 EmailFunction 与 JJEmail 之间设立介面,程序码如下:

public class EmailSystem
{
    private IEmailService EmailService;

    public EmailSystem(IEmailService inEmailService)
    {
        EmailService = inEmailService;
    }

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

        return SendResult;
    }
}

public interface IEmailService()
{
    public string SendEmail(mailAddress, mailMessage);
}

利用建构函式的概念,已经将 EmailSystem 当中的 EmailFunction 这只功能从 JJEmail 抽离,而若要实作该介面(如利用 JJEmail),程序码范例如下:

using JJEmail;

public class DemoJJEmailSerivce : IEmailService
{
    var EmailService = new JJEmailService();
    
    public string SendEmail(mailAddress, mailMessage)
    {
        var EmailFinalResult = EmailServiece
                              .SendEmail(mailAddress, mailMessage);
        
        return EmailFinalResult;
    }
}

而此时的流程图已改成如下:

https://ithelp.ithome.com.tw/upload/images/20210912/201273785bG8xJevnV.png


OK,介面抽离的部分终於处理完了,可以到这次的重点:虚设常式 (Stub),以这个例子,虚设常式要做的事情就是把 IEmailService 的功能实作出来并执行 EmailFunction 是否有误。所以,测试码的撰写如下:

using NUnit3;

[TestFixture]
public class EmailSystemUnitTests
{
    [Test]
    public void EmailFunction_Success()
    {
        // Arrange
        StubEmailSerivce stubEmailService = new StubEmailSerivce();
        
        EmailSystem EmailService = new EmailSystem(stubEmailService);
        
        // Act
        var stubResult = EmailSystem
                        .EmailFunction("[email protected]", "Test Demo");
        
        // Assert
        Assert.AreEqual("Success", stubResult);
    }
}

public class StubEmailSerivce : IEmailService
{
    public string SendEmail(EmailAddress, EmailMessage)
    {
        return "Success";
    }
}

好,看到这边,会注意到 StubEmailService 把 DemoJJEmailSerivce 的实作给替换掉,换成一只不管参数是什麽,都一定会回传 "Success" 的功能;但是,如果到这边就结束,其实有点在做白工,因为特定写了一个百分之百会回传 "Success" 的方法,然後再呼叫这只方法验证是否其正确,在实务上是一件很奇怪的事情。

所以接下来明天会再针对这部分在做进一步探讨,探讨如果 EmailFunction 逻辑再扩充,对於测试上的影响,以及 Stub 真正的用意是什麽。


<<:  #10. Drag & Drop(原生JS版)

>>:  React Native 的动画好帮手:Lottie

Day 11 ROS Cpp Parameter Server

严格来说 Parameter Server 其实不太可以说是一种通讯方式,而是静态储存变数的一种方法...

混合模式-30天学会HTML+CSS,制作精美网站

「混合模式」是什麽呢?有用过photoshop的设计师对图片混合模式肯定不陌生,是元素重叠部分的颜色...

Day 29 -- Stimulus with Rails 6

Stimulus 可以说是 ㄧ种 Rails 专属的『轻量级』 JavaScript 框架。大概是因...

管理 Spring boot 或其他应用程序容器 - Portainer

当容器服务越来越多时,发现使用 CLI 方式进行管理或是除错会有点些许麻烦,如果跨多个 EC2 更加...

Day 23 - 影像处理篇 - 影像与色彩 - 成为Canvas Ninja ~ 理解2D渲染的精髓

老实说我决定要写影像处理这个部分的时候还蛮犹豫的,因为在javascript 做影像处理的这个领域,...