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

看程序码说故事-3

在昨天 Day-10 把 EmailSystem 从 JJEmail 这只套件抽离;同时,在测试方面也针对 EmailFunction 撰写了一只带有虚设常式的测试,可以看到在最後测试的时候写了一只百分百会回传 "Success" 的功能。

然而,这样的测试实际上是没有意义的;其原因在於

  1. 实际商业逻辑上并不会去呼叫 StubEmailSerivce,而是用呼叫第三方套件的 DemoJJEmailSerivce。
  2. StubEmailSerivce 的 SendEmail 百分百是回传 "Success",如果验证失败也只是代表在撰写假物件的过程中有误,增加开发成本。
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";
    }
}

那既然如此,为何还需要虚设常式呢?在这之前,我们先换种角度观察,来看看商业逻辑的流程,也就是 EmailFunction。

在昨天 Day-10 中,我们有提到 EmailSystem 的 EmailFunction 目前的功能:

  1. 利用 EmailServiece 的 SendEmail 方法取得寄信结果 EmailFinalResult (string 格式)。
  2. 回传 EmailFinalResult。
public class EmailSystem
{
    ...

    public string EmailFunction(string EmailAddress, string EmailMessage)
    {
        var EmailFinalResult = EmailServiece.SendEmail(EmailAddress, EmailMessage);

        return EmailFinalResult;
    }
}

那假设今天变更需求,要在寄送 Email 之前确认 EmailMessage 是否带有脏字(是否定义为脏字牵涉到语义学,为了不模糊主题,我们仅侦测是否带有“傻瓜”字眼),若不符合条件则回传失败。因此,程序码改写如下:

public class EmailSystem
{
    ...

    public string EmailFunction(string EmailAddress, string EmailMessage)
    {
        // 确认是否带有脏字
        var SendEmail = false;
        
        if (!EmailMessage.Contains("傻瓜"))
        {
            SendEmail = true;
        }
        
        // 寄送 E-mail 方法
        var EmailFinalResult = "Fail";
        
        if (SendEmail == true)
        {
            var EmailFinalResult = EmailServiece.SendEmail(EmailAddress, EmailMessage);
        } 

        return EmailFinalResult;
    }
}

写到这边,是不是测试的项目也要随之变动了,而不再是单纯测试是否会回传 “Success” 这个功能。而是要针对是否带有“傻瓜”字眼判别寄信成果;因此,单元测试程序码如下:

using NUnit3;

[TestFixture]
public class EmailSystemUnitTests
{
    [Test]
    public void EmailFunction_NotContainFool_Success()
    {
        // Arrange
        StubEmailSerivce stubEmailService = new StubEmailSerivce();
        
        EmailSystem EmailService = new EmailSystem(stubEmailService);
        
        // Act
        var Result = EmailSystem.EmailFunction("[email protected]", "Test Demo");
        
        // Assert
        Assert.AreEqual("Success", Result);
    }
    
    [Test]
    public void EmailFunction_ContainFool_Fail()
    {
        // Arrange
        StubEmailSerivce stubEmailService = new StubEmailSerivce();
        
        EmailSystem EmailService = new EmailSystem(stubEmailService);
        
        // Act
        var Result = EmailSystem.EmailFunction("[email protected]", "傻瓜 呵呵");
        
        // Assert
        Assert.AreEqual("Fail", Result);
    }
}

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

所以,在这边测试的目的就很明确了,就是要测试是否有正确判别 EmailMessage 是否能针对字串带有 “傻瓜” 的字眼做出正确的判别。而 StubEmailSerivce 所做的事情就是要把 EmailServiece.SendEmail(EmailAddress, EmailMessage) 的影响排除掉。

以作者自己的观点,微软大多很热门的套件大多不会有出错的可能性,但今天是使用合作公司或来路不明的 .dll 档案(举例来说,在政府接专案可能是承接前一家厂商做到一半的东西,而交接东西不完全的情况)。此时,这个 .dll 黑盒子的可信度就有待评估。因此,透过虚设常式就可以过滤这种风险。

明天会开始介绍虚设常式的好兄弟——模拟物件 (Mock)。


<<:  虾皮 Open Platform 与经典程序流程图

>>:  Chapter1-DJ最爱的音频动感图像(III)妈妈叫你不要玩音乐,现在知道当DJ很难了吧

JS Library 学习笔记:首先当然来试试 jQuery (一)

要撰写前端功能,直接使用JavaScript是绝对可行的,但要更有效率、具有良好开发体验的话,使用L...

[Day 27] - React 前端串後端 - Cookie存取

目前在浏览器储存使用者资料的主流方式有两种, 一种是存local storage、一种是存在Cook...

能够滑起来的UICollectionView Day9

今天恢复了点元气,终於能好好做事了。 萤幕录制 2021-09-13 下午7.44.19.mov 目...

Splunk-SPL

index=mft_log sourcetype="mft:xferlog" ...

实作四则运算:条件式 when else

「学姐,我这样的进度真的赶得上期末考吗?」经过上午的事,诗忆一整天都有些焦虑不安,唯心刚进教室她就忍...