分享

做好单元测试,你不能不会的Mock

 TestOps云层 2021-06-22

为了隔离其他函数、类或者接口,在做测试的过程中,尤其是单元测试的过程中,Mock 是少不了的技术了。

今天这篇文章就给大家介绍一下 Python 的Mock 技术

Mock 介绍

Mock 是允许用模拟对象替换测试中的系统部件,并断言它们是如何被使用的一项技术。

在软件测试中,Mock 的作用如下:

  • 解决依赖问题:当测试一个接口或者功能模块的时候,如果这个接口或者功能模块依赖其他接口或其他模块,那么如果所依赖的接口或功能模块未开发完毕,那么我们就可以使用Mock模拟被依赖接口,完成目标接口的测试。

  • 单元测试:如果某个功能未开发完成,又要进行测试用例的代码编写,也可以先模拟这个功能进行测试。

  • 模拟复杂业务的接口:实际工作中如果我们在测试一个接口功能时,如果这个接口依赖一个非常复杂的接口业务或者来源于第三方接口,那么我们完全可以使用Mock来模拟这个复杂的业务接口,其实这个和解决接口依赖是一样的原理。

  • 前后端联调:进行前后端分离编程时,如果进行一个前端页面开发,需要根据后台返回的状态展示不同的页面,那么就需要调用后台的接口,但是后台接口还未开发完成,完全可以借助mock来模拟后台这个接口返回想要的数据。

在Python中 Mock 原本是一个独立的第三方模块,现在已经整合到单元测试框架-UnitTest中,可见Mock相对于单元测试的重要性了。

在unittest.mock 模块中,使用 Mock 和 MagicMock对象来替代掉指定的Python对象,以达到模拟对象的行为。

The Mock Class

Mock 是一个灵活的模拟对象,旨在整个代码中取代桩代码(Stub)和测试替身(test doubles)。当我们访问mock对象时,它将为属性创建新的模拟,访问相同的属性将始终返回相同的模拟。Mock 对象将记录如何使用它们,并允许在模拟完成后进行断言处理。

Mock对象的一般用法:

1.找到要替换的对象,这个对象可以是一个类,或者是一个函数,或者是一个类实例;

2.然后实例化Mock类得到一个mock对象,并且设置这个mock对象的行为,比如被调用的时候返回什么值,被访问成员的时候返回什么值等;

3.使用这个mock对象替换掉我们想替换的对象,也就是步骤1中确定的对象;

4.之后就可以开始写测试代码,这个时候我们可以保证我们替换掉的对象在测试用例执行的过程中行为和我们预设的一样。

示例:

被测代码 client.py

class VisitWebSite():

    def sendRequest(self, utl):

        """ 此处代码未完成 """

        pass

    def visitTestOps(self):

        resultCode = self.sendRequest("http://www.")

        if resultCode == "200":

            print("访问成功")

            return "200"

        elif resultCode == "404":

            print("该地址无法访问")

            return "404"

        else:

            print("无效应答码")

            return ""

测试代码:

import unittest

from unittest import mock

from client import VisitWebSite

class VisitTest(unittest.TestCase):

    def test_success_request(self):

        visit = VisitWebSite()

        visit.sendRequest = mock.Mock(return_value="200")

        result = visit.visitTestOps()

        self.assertEqual(result, "200")

    def test_failed_request(self):

        visit = VisitWebSite()

        visit.sendRequest = mock.Mock(return_value="404")

        result = visit.visitTestOps()

        self.assertEqual(result, "404")

Mock 对象常用参数:

name: 这个参数是用来命名一个mock对象,只是起到标识作用,当print一个mock对象的时候,可以看到它的name;

return_value: 这个参数可以指定一个值(或者对象),当mock对象被调用时,如果side_effect函数返回的是DEFAULT,则对mock对象的调用会返回return_value指定的值;

side_effect: 这个参数指向一个可调用对象,一般就是函数。当mock对象被调用时,那么以该函数的返回值作为mock对象调用的返回值。

side_effect示例:

def side_effect_function(url):

return "400"

class VisitTest(unittest.TestCase):

   def test_success_request_se(self):

        visit = VisitWebSite()

        visit.sendRequest = mock.Mock(side_effect=side_effect_function)

        result = visit.visitTestOps()

        self.assertEqual(result, "")

patch方法

patch函数会返回一个mock内部的类实例,这个类是class _patch。返回的这个类实例既可以作为函数的装饰器,也可以作为类的装饰器,也可以作为上下文管理器。使用patch的目的是为了控制mock的范围,意思就是在一个函数范围内,或者一个类的范围内,或者with语句的范围内mock掉一个对象。

示例:

class VisitTest(unittest.TestCase):

   def test_success_request_patch(self):

        mock_sendRequest = mock.Mock(return_value="200")

        with mock.patch('client.VisitWebSite.sendRequest', mock_sendRequest):

            visit = VisitWebSite()

            result = visit.visitTestOps()

            self.assertEqual(result, "200")

The MagicMock Class

MagicMock 是 Mock 的子类,也是用来作为测试替身,用来替代不可被调用的函数或者类。其用法与Mock 对象类似。

示例:

class VisitTest(unittest.TestCase):

def test_success_request_magic(self):

        visit = VisitWebSite()

        visit.sendRequest = mock.MagicMock(return_value="200")

        result = visit.visitTestOps()

        self.assertEqual(result, "200")

微信号 : TestOps

知乎:@TestOps云层

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多