单元测试之Stub和Mock

实例

Analyze类会检查filename的长度,如果小于8,我们就会使用一个实现IWebService的类来记录错误.

我们需要给Analyze方法写单元测试。

python 复制代码
public class LogAnalyzer
{
    private IWebService service;
    private IEmailService email;

    public IWebService Service
    {
        get { return service; }
        set { service = value; }
    }

    public IEmailService Email
    {
        get { return email; }
        set { email = value; }
    }

    public void Analyze(string fileName)
    {
        if (fileName.Length < 8)
        {
            try
            {
                service.LogError("the file name is to short" + fileName);
            }
            catch (Exception e)
            {
                email.SendEmail("From@test.com", "To@test.com", "IWebServiceFailed", e.Message);
            }
        }
    }
}

如果你想学习性能测试,我这边给你推荐一套视频,这个视频可以说是B站播放全网第一的自动化测试教程,同时在线人数到达1000人,并且还有笔记可以领取及各路大神技术交流:798478386

【已更新】B站讲的最详细的Python接口自动化测试实战教程全集(实战最新版)_哔哩哔哩_bilibili【已更新】B站讲的最详细的Python接口自动化测试实战教程全集(实战最新版)共计200条视频,包括:1、接口自动化之为什么要做接口自动化、2、接口自动化之request全局观、3、接口自动化之接口实战等,UP主更多精彩视频,请关注UP账号。https://www.bilibili.com/video/BV17p4y1B77x/?spm_id_from=333.337.search-card.all.click

设计测试用例

测试用例一:

fileName= "c:\test\test.txt" (长度大于8),

期待测试结果: 不会发邮件

测试用例二:

fileName="c:\",(长度小于8), 并且记log失败 。

期待测试结果: 发邮件

如果给Analyze方法写单元测试,为了实现测试用例二。 这时候我们就会碰到两个问题。

第一: 我们无法控制让Service对象记log时抛出异常. 因为Serveice对象我们无法控制

第二: 我们无法判断,Email对象是否发送了Email, (我们不能去Outlook查看收到邮件没有,这样就不是自动化了)

外部依赖对象

对于LogAnalyzer对象来说, Service和Email就是两个外部依赖对象. 我们需要自己写Stub和Mock来模拟这两个外部依赖对象。这样我们才能控制他们。

我们在测试的代码中新建StubWebService和MockEmailService.这两个class分别实现了IWebService和IEmailService.

python 复制代码
public class StubWebService : IWebService
{
    public void LogError(string message)
    {
        throw new Exception("StubWebService throw exception");
    }
}

public class MockEmailService : IEmailService
{
    public string To;
    public string From;
    public string Subject;
    public string Message;

    public void SendEmail(string to, string from, string subject, string message)
    {
        To = to;
        From = from;
        Subject = subject;
        Message = message;
    }
}

工作流程图如下

最后我们来看看我们的测试代码,

我们把StubWebService和MockEmailService两个类的实例注入到产品代码中。(因为多态特性嘛)。

通过控制StubWebService中的LogError方法,抛出一个异常。

然后判断MockEmailService中的SendEmail方法有没有被调用. 被调用了说明发送了Email(我们不需要真的收到一封邮件,因为SendEmail功能是IEmailService实现的,)

python 复制代码
[TestMethod]
public void TestMethod1()
{
    StubWebService stubWebService = new StubWebService();
    MockEmailService mockEmailSender = new MockEmailService();

    LogAnalyzer log = new LogAnalyzer();
    log.Emailservice = mockEmailSender;
    log.WebService = stubWebService;

    // Act
    string tooShortFileName = "1.txt";
    log.Analyze(tooShortFileName);

    // Assert
    Assert.AreEqual("to@test.com", mockEmailSender.To);
    Assert.AreEqual("from@test.com", mockEmailSender.From);
    Assert.AreEqual("WebSerive log error", mockEmailSender.Subject);
}

Stub和Mock的相同处

从上面的例子我们可以看出, Stub和Mock都是模拟外部依赖,以便我们能控制。

Stub 和Mock 的区别

Stub是完全模拟一个外部依赖, 而Mock用来判断测试通过还是失败

良好的产品代码才能单元测试

如果产品代码是下面那样,你就没办法测试了。 因为WebService和EmailService两个类没有继承接口。我们无法把StubWebService和MockEmailService两个类注入到产品代码。

python 复制代码
    public class LogAnalyzer
    {
        private WebService webService;
        private EmailService emailService;

        public WebService WebService
        {
            get { return webService; }
            set { webService = value; }
        }

        public EmailService Emailservice
        {
            get { return emailService; }
            set { emailService = value; }
        }

        public void Analyze(string fileName)
        {
            if (fileName.Length < 8)
            {
                try
                {
                    WebService.LogError("Filename too short:" + fileName);
                }
                catch (Exception e)
                {
                    Emailservice.SendEmail("to@test.com", "from@test.com", "WebSerive log error", e.Message);
                }
            }
        }
    }

Mock框架

其实我们没有必要自己写MockEmailService方法。 已经有现成的Mock框架可以用了, .NET中有Rhino Mock 和 Moq, 这两个框架比较好用

相关推荐
迅猛龙办公室42 分钟前
python实现倒序输出数字
开发语言·python
wuyk5557 小时前
《WiFi 嵌入式物联网开发全套实战》| 第 33 章 Wireshark 无线抓包环境搭建、802.11 帧过滤规则
物联网·测试工具·wireshark
天启HTTP8 小时前
爬虫防封核心原理:IP轮换机制与风控规避逻辑
linux·服务器·网络·爬虫·tcp/ip
运维行者_8 小时前
网络性能监控怎么做?从自动发现到根因分析的4个环节
运维·服务器·网络·人工智能·支持向量机
全栈练习生10 小时前
AI Agent 沙箱
python·ai
hz5678911 小时前
涉密视频会议设备配置指南:终端、音视频采集与配套设施选型
服务器·网络·数据库·安全·实时音视频·信息与通信·智能硬件
广州浮点FLOATLIC11 小时前
许可证服务器迁移后软件打不开:研发 IT 怎样定位连接问题
linux·服务器·数据库
优橙教育11 小时前
零基础学AI应用开发要多久?3个月能到什么水平
服务器·开发语言·网络·php
AIgorithmGEEK11 小时前
[Linux]从手写报头到内核套路:序列化、反序列化与自定义协议全链路
linux·运维·服务器·网络·序列化·反序列化
SEO_juper11 小时前
用 Python 写一个 GEO 可见性检查脚本:你的网站现在能被 AI 引用吗
开发语言·人工智能·爬虫·python·seo·外贸独立站