• python mock使用


    Overview

    mock 是一个用于单元测试的 Python 库,它使用 mock 模拟系统中如 class, method 等部分,并且断言它们是如何被调用的。在编写单元测试时,mock 非常适合模拟数据库,web 服务器等依赖外部的场景。本文是 mock 的入门篇,主要介绍 mock 的基本用法。

    除了 mock 外,还有许多其它的 mocking 库,Python Mock Library Comparison 在用法上对这些库做了简单的比较,其中 OpenStack 单元测试广泛的使用了 mock 和 mox。

    mock 的安装非常简便:

    $ pip install mock
    

    Mock Patching Methods

    当使用 mock 模拟 methods 时,mock 会替换被模拟的 methods,并且记录调用详情。

    >>> class Foo(object):
    ...     def echo(self, *args):
    ...         return "hello"
    ...
    >>>
    >>> foo = Foo()
    >>> foo.echo = mock.MagicMock()
    >>> foo.echo.return_value = "mock value"
    >>>
    >>> foo.echo()
    'mock value'
    >>> foo.echo(1, 2)
    'mock value'
    

    被模拟后,foo.echo 的类型是一个名为 mock.MagicMock 类,具有 assert_any_call, assert_called_once_with 等方法,其中 assert 类型的方法通常用于检验 foo.echo 是否被正确调用。

    >>> type(foo.echo)
    <class 'mock.MagicMock'>
    
    >>> dir(foo.echo)
    ['assert_any_call', 'assert_called_once_with', 'assert_called_with',
    'assert_has_calls', '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']
    

    断言 foo.echo 被调用的情况,其中 foo.echo 共被调用两次(见上)。

    >>> foo.echo.called
    True
    >>> foo.echo.call_count
    2
    >>> foo.echo.mock_calls
    [call(), call(1, 2)]
    >>>
    >>> foo.echo.assert_called_with(1, 2)
    >>> foo.echo.assert_called_with(1)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/lib/python2.7/dist-packages/mock.py", line 844, in assert_called_with
        raise AssertionError(msg)
    AssertionError: Expected call: mock(1)
    Actual call: mock(1, 2)
    

    mock.Mock 和 mock.MagicMock 是两个常用的类,stackoverflow 有篇帖子 mock-vs-magicmock 专门讲述二者的区别:

    • MagicMock 是 Mock 的之类
    • MagicMock 额外实现了很多 magic 的方法

    Mocking Classes

    采用 mock 可方便的模拟 class,例如:

    >>> def some_function():
    ...     foo = Foo()
    ...     return foo.echo()
    ...
    >>> with mock.patch('__main__.Foo') as foo_mock:
    ...     instance = foo_mock.return_value
    ...     instance.echo.return_value = "mock result"
    ...     result = some_function()
    ...     assert result == "mock result"
    ...
    >>> print some_function()
    hello
    

    值得注意的是,mock.patch 把模拟的效果限制在 with 作用域的范围内,所以 with 作用域之外的 some_function 的返回值依旧为 hello。


    Setting Return Values and Attributes

    mock 同样可方便的模拟返回值和 attributes,例如模拟一个对象的返回值,

    >>> value_mock = mock.Mock()
    >>> value_mock.return_value = 3
    >>> value_mock()
    3
    

    模拟一个方法的返回值:

    >>> method_value_mock = mock.Mock()
    >>> method_value_mock.method.return_value = 3
    >>> method_value_mock.method()
    3
    

    模拟对象的 attribute:

    >>> attr_mock = mock.Mock()
    >>> attr_mock.x = 3
    >>> attr_mock.x
    3
    

    参数 side_effect

    side_effect 是一个非常有用的参数,大大提高了 mock 返回值的灵活性,它可以是一个异常、函数或者可迭代对象。例如返回一个异常:

    >>> except_mock = mock.Mock(side_effect=Exception('Boom!'))
    >>> except_mock()
    Traceback (most recent call last):
      ...
    Exception: Boom!
    

    当 side_effect 为迭代对象时,样例如下:

    >>> iter_mock = mock.Mock(side_effect=[1, 2, 3])
    >>> iter_mock()
    1
    >>> iter_mock()
    2
    >>> iter_mock()
    3
    >>> iter_mock()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/Library/Python/2.7/site-packages/mock/mock.py", line 1062, in __call__
        return _mock_self._mock_call(*args, **kwargs)
      File "/Library/Python/2.7/site-packages/mock/mock.py", line 1121, in _mock_call
        result = next(effect)
      File "/Library/Python/2.7/site-packages/mock/mock.py", line 127, in next
        return _next(obj)
    StopIteration
    

    单 side_effect 为函数时,样例如下:

    >>> def side_effect(value):
    ...     return value
    ...
    >>>
    >>> side_effect_mock = mock.Mock(side_effect=side_effect)
    >>> side_effect_mock(1)
    1
    >>> side_effect_mock("hello world!")
    'hello world!'
  • 相关阅读:
    Java利用Base64编码和解码图片文件
    SQL查询结果列拼接成逗号分隔的字符串:group_concat
    两个正则表达式:匹配固定电话号码,匹配手机号码
    IDEA导入Junit jar包,在JavaSE的Module中使用Junit测试
    如何正确遍历删除List中的元素(普通for循环、增强for循环、迭代器iterator、removeIf+方法引用)
    Java Springboot 根据图片链接生成图片下载链接 及 多个图片打包zip下载链接
    fastjson List<> 转Json , Json 转List<>
    PHP结合memcacheq消息队列解决并发问题
    Redis与Memcached的区别
    yii2 中excel表导出
  • 原文地址:https://www.cnblogs.com/bonelee/p/12110985.html
Copyright © 2020-2023  润新知