zoukankan      html  css  js  c++  java
  • Mock数据

    楔子

    现在, 要测试这些接口:

    """
    用例集
    case_set.py
    pip install requests
    """
    import requests
    
    def v2ex_info():
        """
        获取v2ex的网站信息
        https://www.v2ex.com/api/site/info.json
    
        """
        response = requests.get(url='https://www.v2ex.com/api/site/info.json')
        return response.json().get('title')  # V2EX
    
    def v2ex_stats():
        """
        获取v2ex的网站信息
        https://www.v2ex.com/api/site/stats.json
        """
        response = requests.get(url='https://www.v2ex.com/api/site/stats.json')
        return response.json().get('member_max')  # int类型
    
    def cnodejs():
        """ 获取 cnodejs,推荐博客总数 """
        response = requests.get('https://cnodejs.org/api/v1/topics')
        return response.json().get('success')  # True
    
    if __name__ == '__main__':
        print(v2ex_info() == 'V2EX')
        print(type(v2ex_stats()) is int)
        print(cnodejs() is True)
    View Code

    关于requests模块, see also:https://www.cnblogs.com/sundawei7/p/11949153.html

    规则是:

    • v2ex_info接口返回值中的title是V2EX才算通过。
    • v2ex_stats接口返回值中的member_max是int类型才算通过。
    • cnodejs接口只值中的success是True算通过。

    根据规则很快的写出了测试用例:

    """
    用例类
    myMain.py
    """
    
    import unittest
    from case_set import v2ex_stats, v2ex_info, cnodejs
    
    class InterfaceCase(unittest.TestCase):
    
        def test_v2ex_stats(self):
            """ 测试 v2ex_stats 接口,返回: int类型"""
            self.assertIs(type(v2ex_stats()), int)
    
        def test_v2ex_info(self):
            """ 测试 v2ex_info 接口, 返回: V2EX """
            self.assertEqual(v2ex_info(), 'V2EX')
    
        def test_cnodejs(self):
            """ 测试 cnodejs 接口,返回: True """
            self.assertIs(cnodejs(), True)
    
    if __name__ == '__main__':
        unittest.main()
    View Code

    结果也OK:

    M:	ests>python36 myMain.py -v
    test_cnblogs_info (__main__.InterfaceCase)
    测试博客园接口,返回: 200 ... ok
    test_v2ex_info (__main__.InterfaceCase)
    测试 v2ex_info 接口, 返回: V2EX ... ok
    test_v2ex_stats (__main__.InterfaceCase)
    测试 v2ex_stats 接口,返回: int类型 ... ok
    
    ----------------------------------------------------------------------
    Ran 3 tests in 3.075s
    
    OK
    View Code

    为什么需要mock

    在反复的执行测试用例时,发现test_cnodejs用例执行有些问题。有时候执行失败有时候成功,并且就算成功也响应时间较长,一番分析后,发现不是自己的问题,是接口暂时开发的不是很完善,导致现在测试不稳定。 但是你根据接口文档知道,这个接口这么测试,只要返回True就算通过。 那么能不能我们自己模拟出来这么一个接口,然后模拟一些方法和数据,在测试环境下使用。

    什么是mock 在协同开发、测试中,总会出现各种问题,比如:

    • 开发人员某些接口还没有开发完毕。
    • 与第三方联调时,第三方拖了后腿,没准备好环境、数据都有可能。比如说我们测试的某个接口本身没有问题,但它依赖的某个接口有些问题,这就影响我们的正常测试任务进度。
    • 测试环境恶劣。
    • 开发只提供接口,数据自己搞!

    这些问题总能影响我们的测试进度,那么我们怎么正常的展开呢? 这就需要mock来解决了。

    什么是mock mock是在测试过程中,对于一些不容易构造/获取的对象,创建一个mock对象来模拟对象的行为。 mock测试一般也称为mock数据。 简单来说,mock就是向测试对象提供一套和测试资源完全相同的接口和方法,不关系具体的实现过程,只关心具体结果。 mock测试的优点

    • 团队并行工作:有了mock,前后端人员只需要定义好接口文档就可以开始并行的工作,互不影响,只需要在最后联调的时候多多交流即可。后端与后端之间如果有接口耦合,也同样能被Mock解决;测试过程中如果遇到依赖接口没有准备好,同样可以借助Mock;不会出现一个团队等待另一个团队的情况。这样的话,开发自测阶段就可以及早开展,从而发现缺陷的时机也提前了,有利于整个产品质量以及进度的保证。
    • 开启TDD模式,即测试驱动开发:单元测试是TDD实现的基石,而TDD经常会碰到协同模块尚未开发完成的情况,但是有了mock,这些一切都不是问题。当接口定义好后,测试人员就可以创建一个Mock,把接口添加到自动化测试环境,提前创建测试。
    • 模拟出无法访问的资源:比如说,你需要调用一个“墙”外的资源来方便自己调试,就可以自己Mock一个。
    • 系统隔离:假如我们需要调用一个post请求,为了获得某个响应,来看当前系统是否能正确处理返回的“响应”,但是这个post请求会造成数据库中数据的污染,那么就可以充分利用Mock,构造一个虚拟的post请求,我们给他指定返回就好了。
    • 产品展示:假如我们需要创建一个演示程序,并且做了简单的UI,那么在完全没有开发后端服务的情况下,也可以进行演示。说到演示了,假如你已经做好了一个系统,并且需要给客户进行演示,但是里面有些真实数据并不想让用户看到,那么同样,你可以用Mock接口把这些敏感信息接口全部替换。
    • 测试覆盖:假如有一个接口,有100个不同类型的返回,我们需要测试它在不同返回下,系统是否能够正常响应,但是有些返回在正常情况下基本不会发生,难道你要千方百计地给系统做各种手脚让他返回以便测试吗?比如,我们需要测试在当接口发生500错误的时候,app是否崩溃,别告诉我你一定要给服务端代码做些手脚让他返回500 。。。而使用mock,这一切就都好办了,想要什么返回就模拟什么返回,妈妈再也不用担心你的测试覆盖度了。

    关于TDD,see also:https://baike.baidu.com/item/TDD/9064369?fr=aladdin关于测试覆盖,see also:https://www.cnblogs.com/sundawei7/p/11944489.html

    如何mock数据

    下载安装

    这里需要用到mock模块了,在Python3.x中,mock被集成到了unittest中,无需下载,直接导入即可,但在Python2.x中,就需要:

    pip install mock
    

    mock类的构成

    这里以Python3.x为例。

    快速上手

    构造器:_init_

    from unittest import mock
    
    mock_obj = mock.Mock()
    print(mock_obj)  # <Mock id='10069264'>
    print(dir(mock_obj))
    '''
    [
        'assert_any_call', 'assert_called', 'assert_called_once', 
        'assert_called_once_with', 'assert_called_with', 'assert_has_calls', 
        'assert_not_called', 'attach_mock', 'call_args', 
        'call_args_list', 'call_count', 'called', 
        'configure_mock', 'method_calls', 'mock_add_spec', 
        'mock_calls', 'reset_mock', 'return_value', 
        'side_effect'
    ]
    '''
    View Code

    虽然__init__是实例化方法,但在这里通常被称为构造器。 由打印结果可以看到,通过mock.Mock()实例化出一个mock对象mock_obj。这个对象是继承了Mock类的属性和方法。这样的一个mock对象对我们来说用处不大。 我们来试着添加一些自定义属性和方法,使之更灵活。 在Mock实例化时,我们可以传入这些参数:

    • name:mock对象的名字。它只是起到标识作用,当你print一个有name的mock对象时,可以看到它的name。
    • spec:mock对象的属性值。
    • side_effect:该参数指向一个可调用对象(一般是函数),当mock对象被调用时,如果该参数的返回值是默认的DEFAULT,则mock对象返回return_value指定的值,否则返回side_effect指定的对象的返回值。
    • return_value:该参数指定一个值或者对象,当mock对象被调用时,如果side_effect函数的返回值是DEFAULT,那么mock对象返回return_value指定的值或者对象。

    注意,如果side_effect和return_value同时存在的时候,side_effect将会覆盖return_value。

    name

    from unittest import mock
    
    mock_obj1 = mock.Mock()
    mock_obj2 = mock.Mock(name='mock_obj2')
    print(mock_obj1)  # <Mock id='50111760'>
    print(mock_obj2)  # <Mock name='mock_obj' id='53781776'>
    View Code

    name参数没啥好说的,就是跟mock对象起了个名字。

    为return_value指定某个值 现在让我们使用mock来模拟出文章开头的那几个接口测试中的cnodejs接口。

    import unittest
    from unittest import mock
    from case_set import cnodejs  # 导入真实的cnodejs接口函数
    
    class CnodejsTestCase(unittest.TestCase):
    
        def test_mock_cnodejs(self):
            """ 使用 mock 模拟的 cnodejs 接口 返回: True"""
            # 构造mock对象
            cnodejs = mock.Mock(return_value=True)
            # 使用mock对象进行断言
            self.assertIs(cnodejs(), True)
    
        def test_cnodejs(self):
            """ 测试 cnodejs 接口,返回: True """
            self.assertIs(cnodejs(), True)
    
    
    if __name__ == '__main__':
        unittest.main()
    View Code

    用例test_mock_cnodejs方法中: 在Mock类实例化时传入return_value参数,然后构造出的mock对象赋值给cnodejs变量。然后cnodejs()相当于调用mock对象,得到返回值True,完事拿着这个返回值使用unittest进行断言。 用例test_cnodejs方法中,正常写测试用例断言,以判断两个用例方法有什么不同之处:

    test_cnodejs (__main__.CnodejsTestCase)
    测试 cnodejs 接口,返回: True ... ok
    test_mock_cnodejs (__main__.CnodejsTestCase)
    使用 mock 模拟的 cnodejs 接口 返回: True ... ok
    
    ----------------------------------------------------------------------
    Ran 2 tests in 1.097s
    
    OK
    View Code

    可以看到,两个用例方法都通过了,并没有什么区别。 在测试环境下,使用mock模拟的方法进行测试,这样能尽早的介入测试,带来的优势不一而足。 为return_value指定类的对象 return_value除了上述用法,还可以指定类的对象:

    from unittest import mock
    
    
    class Foo(object):
        """ 自定义类 """
    
        def f1(self):
            return 'this is Foo.f1'
    
        def f2(self, name):
            return name
    # 正常的类的实例化与调用
    foo_obj = Foo()
    print(foo_obj.f1())  # this is Foo.f1
    print(foo_obj.f2('this is Foo.f2'))  # this is Foo.f2
    
    # 构造mock对象并传入 Foo实例化对象
    foo_Class = mock.Mock(return_value=Foo())
    # 想要得到mock对象的返回值,必须调用,也就是加括号
    foo_obj = foo_Class()  # mock对象调用得到return_value值也就是Foo的实例化对象
    # 接下里就是正常的调用了
    print(foo_obj.f1())  # this is Foo.f1
    # 同样可以正常传参
    print(foo_obj.f2('this is Foo.f2'))  # this is Foo.f2
    View Code

    使用mock对象模拟类的实例化对象同样方便。

    side_effect 先来看第一个示例,可以为mock对象的side_effect参数指定可迭代对象。

    from unittest import mock
    
    mock_obj1 = mock.Mock(return_value=100)
    print(mock_obj1())  # 100
    mock_obj2 = mock.Mock(return_value=100, side_effect=[200, 300])
    print(mock_obj2())  # 200
    View Code

    由上例可以看到,如果在构造mock对象的时候,只有return_value被指定,调用mock对象返回return_value指定的值。 当side_effectreturn_value同时被指定时,side_effect就覆盖了return_value。 那么既然side_effect接受的是一个可迭代对象,就可以多次调用它:

    from unittest import mock
    
    mock_obj1 = mock.Mock(return_value=100)
    print(mock_obj1())  # 100
    mock_obj2 = mock.Mock(return_value=100, side_effect=[200, 300])
    print(mock_obj2())  # 200
    print(mock_obj2())  # 300
    print(mock_obj2())  # StopIteration
    View Code

    可以看到side_effect对象本质上是一个生成器。

    为spec指定属性组成的列表 现在使用mock来模拟出来两V2EX的两个接口方法。

    import unittest
    from unittest import mock
    from case_set import v2ex_info, v2ex_stats
    
    # 为mock对象的spec参数传入属性(方法)组成的列表
    spec_list = ['v2ex_info', 'v2ex_stats']
    mock_obj = mock.Mock(spec=spec_list)
    print(spec_list)  # ['v2ex_info', 'v2ex_stats']
    # 根据真实的接口规则设置两个方法的返回值
    mock_obj.v2ex_info.return_value = 'V2EX'
    mock_obj.v2ex_stats.return_value = 466668  # 该接口只需要返回值是int即可
    
    class TestCaseDemo(unittest.TestCase):
    
        def test_v2ex_stats(self):
            """ 测试 v2ex_stats 接口,返回: int类型"""
            self.assertIs(type(v2ex_stats()), int)
    
        def test_mock_v2ex_stats(self):
            """ mock v2ex_stats 接口,返回: int类型 """
            v2ex_stats = mock_obj.v2ex_stats
            self.assertIs(type(v2ex_stats()), int)
    
        def test_mock_v2ex_info(self):
            """ mock v2ex_info 接口, 返回: V2EX """
            v2ex_info = mock_obj.v2ex_info
            self.assertEqual(v2ex_info(), 'V2EX')
    
        def test_v2ex_info(self):
            """ 测试 v2ex_info 接口, 返回: V2EX """
            self.assertEqual(v2ex_info(), 'V2EX')
    
    if __name__ == '__main__':
        unittest.main()
    View Code

    结果:

    M:	ests>python36 myMain.py -v
    test_mock_v2ex_info (__main__.TestCaseDemo)
    mock v2ex_info 接口, 返回: V2EX ... ok
    test_mock_v2ex_stats (__main__.TestCaseDemo)
    mock v2ex_stats 接口,返回: int类型 ... ok
    test_v2ex_info (__main__.TestCaseDemo)
    测试 v2ex_info 接口, 返回: V2EX ... ok
    test_v2ex_stats (__main__.TestCaseDemo)
    测试 v2ex_stats 接口,返回: int类型 ... ok
    
    ----------------------------------------------------------------------
    Ran 4 tests in 3.154s
    
    OK
    View Code

    由结果发现,用mock模拟的两个接口都通过了。 为spec指定类属性

    from unittest.mock import Mock
    class Foo(object):
        age = 20
        def f1(self):
            return 'this if f1'
    
        def f2(self, name):
            return name
    mock_obj = Mock(spec=Foo)
    print(mock_obj.f1)  # <Mock name='mock.f1' id='1847131683640'>
    print(mock_obj.f2)  # <Mock name='mock.f2' id='1847131615128'>
    print(mock_obj.age)  # <Mock name='mock.age' id='1847131718880'>
    print(mock_obj.name)  # AttributeError: Mock object has no attribute 'name'
    View Code

    为mock对象指定了属性为Foo类,那么,类中的方法和属性都是mock对象的属性,这也是前三个打印没有问题的原因,而第4个打印报错了,显然,Foo类中没有一个叫name的属性或者方法。

    mock断言语句

    由mock思维导图知道,mock关于断言有这些常用的:

    • assert_called_with(arg):检查函数调用参数是否正确。
    • assert_called_once_with(arg):检查函数调用参数是否正确,但是只调用一次。
    • assert_any_call():用于检查测试的mock对象在测试例程中是否调用了方法。
    • assert_has_calls():期望调用方法列表。

    assert_called_with assert_called_with检查mock方法是否获取了正确的参数,当至少有一个参数有错误的值或者类型时、当参数的个数出错时、当参数的顺序不正确时,断言失败。

    from unittest.mock import Mock
    
    class Foo(object):
        value = 20
    
        def f1(self, arg):
            return arg
    
        def f2(self, *args):
            return args
    
    mock_obj = Mock(spec=Foo)
    # f1正确的传参姿势
    mock_obj.f1(222)
    # mock_obj.f1.assert_called_with()  # 报错,没有传参
    # mock_obj.f1.assert_called_with(11)  # 报错,瞎98传参
    # mock_obj.f1.assert_called_with('6669')  # 报错,6翻了吧,传值的类型不对
    # mock_obj.f1.assert_called_with(222)  # 噢啦,mock_obj.f1()传的就是 222
    
    # f2正确传参姿势
    mock_obj.f2(1, 2, 3)
    # mock_obj.f2.assert_called_with() # 报错,没有传参
    # mock_obj.f2.assert_called_with(1)  # 报错,少传了参数
    # mock_obj.f2.assert_called_with(1, 3, 2)  # 报错,传参顺序不对
    mock_obj.f2.assert_called_with(1, 2, 3)  # 噢啦,传参姿势很对
    View Code

    assert_called_once_with assert_called_once_with断言,当指定方法被多次调用的时候,断言失败。

    from unittest.mock import Mock
    
    class Foo(object):
        value = 20
    
        def f1(self, arg):
            return arg
    
        def f2(self, *args):
            return args
    # 实例化mock对象
    mock_obj = Mock(spec=Foo)
    # 为f1方法赋返回值
    mock_obj.f1.return_value = 222
    print(mock_obj.f1())
    mock_obj.f1.assert_called_once_with()  # 第一次调用,没问题
    print(mock_obj.f1())
    mock_obj.f1.assert_called_once_with()  # 第二次调用,报错 AssertionError: Expected 'f1' to be called once. Called 2 times.
    View Code

    这个断言相对简单。

    assert_any_call assert_any_call断言用于检查测试执行中的mock对象在测试中是否调用了方法。

    from unittest.mock import Mock
    
    class Foo(object):
        value = 20
    
        def f1(self, arg):
            return arg
    
        def f2(self, *args):
            return args
    
    
    mock_obj = Mock(spec=Foo)
    # mock对象调用了 f1() f1(100) f1(200) f1(200)
    mock_obj.f1()
    mock_obj.f1(100)
    mock_obj.f1(200)
    mock_obj.f1(200)
    
    # 判断:mock对象调用了f1() f1(100) f1(200) f1(300) f2()
    mock_obj.f1.assert_any_call()  # 没错
    mock_obj.f1.assert_any_call(100)  # 没错
    mock_obj.f1.assert_any_call(200)  # 没错
    # mock_obj.f1.assert_any_call(300)  # AssertionError: f1(300) call not found
    mock_obj.f2.assert_any_call()  # AssertionError: f2() call not found
    View Code

    上例,assert_any_call会判断整个测试中方法是否被调用了。而不管该方法是否被重复调用。 例如,在程序执行时执行了mock_obj.f1.assert_any_call(),那么就用mock_obj.f1.assert_any_call()判断刚才的方法是否执行过。执行过啥都不做,要是没执行过就报错。

    assert_has_calls assert_has_calls检查是否按照正确的顺序和正确的参数进行调用的。所以,需要给出一个方法的调用顺序,assert的时候按照这个顺序进行检查。

    from unittest.mock import Mock
    from unittest.mock import call  # 引入新的模块
    
    class Foo(object):
        value = 20
    
        def f1(self, arg):
            return arg
    
    mock_obj = Mock(spec=Foo)
    # 正确的执行顺序是 f1() f1(100) f1(200)
    mock_obj.f1()
    mock_obj.f1(100)
    mock_obj.f1(200)
    
    # 报错, 现在的执行顺序是 f1() f1(100) f1(300)
    # calls_list = [call.f1(), call.f1(100), call.f1(300)]  # 报错,没有 call.f1(300)
    # mock_obj.assert_has_calls(calls_list)
    
    # 报错,现在的执行顺序是 f1(200) f1() f1(300)
    # calls_list = [call.f1(200), call.f1(), call.f1(200)]  # 报错,执行顺序不对
    # mock_obj.assert_has_calls(calls_list)
    
    # 对喽
    calls_list = [call.f1(), call.f1(100), call.f1(200)]
    mock_obj.assert_has_calls(calls_list)
    View Code

    首先,以列表的形式列出方法调用顺序,每个方法前使用call.f1()的形式,因为如果不加call来修饰的话, 解释器将不知道f1是一个方法,当然call在使用之前需要引入。

    mock管理方法

    mock中,关于管理有这些常用方法:

    • attach_mock:将一个mock对象添加到另一个mock对象中。
    • configure_mock,更改mock对象的return_value值。
    • mock_add_spec:给mock对象添加新的属性。
    • reset_mock:将mock对象恢复到初始状态。

    acttach_mock acttach_mock将一个mock对象添加到另一个mock对象中。

    from unittest.mock import Mock
    
    
    class Foo(object):
    
        def f1(self, arg):
            return arg
    
    
    class Bar(object):
    
        def f2(self, *args):
            pass
    
    # 分别构造foo和bar的mock对象
    mock_foo = Mock(spec=Foo)
    mock_bar = Mock(spec=Bar)
    
    # 打印也没问题
    print(mock_foo, mock_bar)  # <Mock spec='Foo' id='57738096'> <Mock spec='Bar' id='130627728'>
    
    # 分别为两个mock对象的方法添加返回值
    mock_foo.f1.return_value = 'Foo.f1'
    mock_bar.f2.return_value = 'Bar.f2'
    
    # 正常的调用都没问题
    print(mock_foo.f1())  # Foo.f1
    print(mock_bar.f2())  # Bar.f2
    
    # 使用attach_mock将mock_bar对象添加到mock_foo中
    mock_foo.attach_mock(mock_bar, 'bar')
    
    # 现在mock_bar对象成为了mock_foo mock对象的一个属性bar
    print(mock_foo.bar)  # <Mock name='mock.bar' spec='Bar' id='132987120'>
    
    # mock_foo.bar等于拿到了mock_bar对象,然后调用其中的f2方法,并且得到了之前赋值的返回值
    print(mock_foo.bar.f2())  # Bar.f2
    View Code

    需要注意的是,attach_mock(self, mock, attribute)必须为添加进来的mock对象指定一个属性名。

    configure_mock

    configure_mock用来更改mock对象的return_value值。

    from unittest.mock import Mock
    
    class Foo(object):
    
        def f1(self, arg):
            return arg
    
        def f2(self, arg):
            return arg
    
    # 实例化mock对象并添加属性和返回值
    mock_obj = Mock(spec=Foo, return_value='abc')
    # 正常调用mock对象得到预期的结果 abc
    print(mock_obj())  # abc
    # 使用configure_mock修改mock对象的return_value值
    mock_obj.configure_mock(return_value='xyz')
    # 修改成功
    print(mock_obj())  # xyz
    
    # 可以批量设置返回值,比如f1方法的返回值为 '100', f2方法的返回值为 200
    spec_dict = {'f1.return_value': '100', 'f2.return_value': 200}
    # 将字典打散后使用configure_mock设置到mock对象中
    mock_obj.configure_mock(**spec_dict)
    print(mock_obj())  # xyz
    print(mock_obj.f1())  # 100  ps:字符串类型的100
    print(mock_obj.f2())  # 2090
    View Code

    mock_add_spec mock_add_spec(self, spec, spec_set=False)用来给mock对象添加一个新的属性,新的属性会覆盖掉原来的属性。spec_set指属性可读可写,默认是只读,但可写我没测试出来....欢迎留言指正。

    from unittest.mock import Mock
    
    class Foo(object):
    
        def f1(self, arg):
            return arg
    
    class Bar(object):
    
        def f2(self, args):
            return args
    
    def ace():
        pass
    
    # 实例化mock对象
    mock_obj = Mock(spec=Foo)
    print(mock_obj.f1())  # <Mock name='mock.f1()' id='119946576'>
    
    # 使用mock_add_spec给mock_obj添加一个新的属性
    mock_obj.mock_add_spec(Bar)
    print(mock_obj.f2())  # <Mock name='mock.f2()' id='46952912'>
    
    # 正常的使用都没问题
    mock_obj.f2.return_value = 'Bar.f2'
    print(mock_obj.f2())  # Bar.f2
    
    # 上面添加的属性是类,现在是函数,记得函数这里没有方法,别瞎点啊
    mock_obj.mock_add_spec(ace)
    mock_obj.return_value = 'function'
    print(mock_obj())  # function
    
    # 另外,新添加的属性会覆盖掉之前的属性。现在的mock对象模拟的函数ace对象,ace函数哪有什么f1啊
    print(mock_obj.f1())  # AttributeError: Mock object has no attribute 'f1'
    View Code

    reset_mock reset_mock将mock对象回复到初识状态,避免了重新构造mock对象带来的开销。

    from unittest.mock import Mock
    
    class Foo(object):
    
        def f1(self, arg):
            return arg
    
    mock_obj = Mock(spec=Foo)
    mock_obj.f1()
    # 这里如果不使用 reset_mock, 那么f1方法就被调用了两次,下面的 assert_called_once_with就会报错,现在则不报错了
    mock_obj.reset_mock()
    mock_obj.f1()
    mock_obj.f1.assert_called_once_with()
    View Code

    mock统计方法

    再来看mock关于统计的一些方法:

    • called:跟踪mock对象所做的任意调用的访问器。
    • mock_calls:显示工厂调用和方法调用。
    • call_args:mock对象的初始化参数。
    • call_args_list:调用中使用参数。
    • call_count:mock对象被调用次数。
    • method_calls:以列表的形式返回mock对象都调用了哪些方法。

    called

    from unittest.mock import Mock
    
    def ace():
        pass
    
    # 构造 mock对象并没有调用
    mock_obj = Mock(spec=ace)
    # OK,此时mock对象没有调用,所以mock_obj.called:False
    print(mock_obj.called)  # False
    # OK,现在调用了,那么 mock_obj.called:True
    mock_obj()
    print(mock_obj.called)  # True
    View Code

    called只要检测到mock对象被调用,就返回True。

    call_count

    from unittest.mock import Mock
    
    def ace():
        pass
    
    mock_obj = Mock(spec=ace)
    mock_obj()
    mock_obj()
    mock_obj()
    print(mock_obj.call_count)  # 3
    View Code

    call_count检查mock对象被调用了多少次。

    call_args && call_args_list

    from unittest.mock import Mock
    
    mock_obj = Mock()
    mock_obj()
    print(mock_obj.call_args)  # call()
    print(mock_obj.call_args_list)  # [call()]
    View Code

    call_args_list以列表的形式返回工厂调用时所有的参数。

    method_calls

    from unittest.mock import Mock
    
    class Foo(object):
    
        def f1(self, arg):
            return arg
    
    mock_obj = Mock(spec=Foo)
    mock_obj()
    mock_obj.f1()
    print(mock_obj.call_args)  # call()
    print(mock_obj.call_args_list)  # [call()]
    print(mock_obj.method_calls)  # [call.f1()]
    View Code

    mock_calls

    from unittest.mock import Mock
    
    class Foo(object):
    
        def f1(self, arg):
            return arg
    
    mock_obj = Mock(spec=Foo)
    mock_obj()
    mock_obj.f1()
    print(mock_obj.mock_calls)  # [call(), call.f1()]
    View Code

    首先,mock对象被调用时,执行工厂call方法,完事第二次调用了f1方法,所以mock_calls返回了两个方法。


    [Mock测试概念介绍](https://www.jianshu.com/p/3944c0b82f30) | [如何 mock 数据](https://www.jianshu.com/p/63056120fab8) | [Python中的模块学习之mock模块](https://blog.csdn.net/peiyao456/article/details/77075173)

  • 相关阅读:
    如何在xml中存储图片
    软件开发平台化催生软件产业链新层级(1)
    在sql server 中如何移动tempdb到新的位置
    Base64在XML中存储图片的解决方案
    东软金算盘VP*台:拆分标准与个性
    浪潮“楼上”开发平台简介
    python模块整理3random模块
    python模块整理1os模块
    python学习笔记18重点和忘记知识点总结
    python模块整理8glob(类似grep)和fnmatch(匹配文件名)
  • 原文地址:https://www.cnblogs.com/sundawei7/p/11947792.html
Copyright © 2011-2022 走看看