mock就是测试过程中,对一些不容易获取的数据,创建一个虚拟的对象以便测试,这个虚拟的对象就是Mock对象。一般用于单元测试或自动化测试依赖第三方接口时应用。
Mock模块 - 图1

init

name

  1. mock对象的名称

    return_value

  2. mock对象被调用的返回值

    side_effect

  3. 覆盖return_value,当mock对象被调用时,返回该值,一般是异常返回或者是一个list/tuple ```python

    mock_test.py

import requests

def mock_request(url): return requests.get(url=url).status_code

def invoke_mock_request(url): return mock_request(url)

  1. ```python
  2. # test_mock_1.py
  3. import pytest
  4. from api_testcases.mock_test import invoke_mock_request, mock_request
  5. def test_mock_init(mocker):
  6. """patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)
  7. target:传入当前需要mock的方法(接口),字符串格式
  8. name:mock对象的名称
  9. return_value:mock对象被调用的返回值
  10. side_effect:覆盖return_value,当mock对象被调用时,返回该值,一般是异常返回或者是一个list/tuple
  11. spec:设置mock对象的属性
  12. """
  13. init_mocker = mocker.patch('api_testcases.mock_test.mock_request', name='test mocker init',
  14. return_vlaue=mock_request)
  15. invoke_mock_request(URL)
  16. init_mocker.assert_called()
  17. side_effect_list = [200]
  18. # 当side_effect被设置的时候,return_value就不起作用了,side_effect被设置为一个异常也可以被指定的参数的值是一个list或者tuple
  19. side_effect_mocker = mocker.patch('api_testcases.mock_test.mock_request', name='test mocker init',
  20. return_vlaue=mock_request, side_effect=side_effect_list)
  21. assert invoke_mock_request(URL) == side_effect_list[0]
  22. side_effect_mocker.assert_called()
  23. if __name__ == "__main__":
  24. pytest.main()
  25. """
  26. ============================= test session starts ==============================
  27. platform darwin -- Python 3.7.7, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
  28. rootdir: /Users/zaygee/pytest_test, configfile: pytest.ini
  29. plugins: allure-pytest-2.9.42, mock-3.6.1, xdist-2.2.1, forked-1.3.0
  30. collected 1 item
  31. test_mock_1.py::test_mock_init PASSED [100%]
  32. ============================== 1 passed in 0.02s ===============================
  33. """

spec

  1. 设置mock对象的属性 ```python

    test_mock_1.py

import pytest

class Foo(object): _num = 10

def test_mocker_spec(mocker):

  1. # 指定属性list
  2. spec_list = ['_value', 'callFunc']
  3. mocker_spec = mocker.patch('api_testcases.mock_test.mock_request', spec=spec_list)
  4. logger.info(mocker_spec._value)
  5. # 执行类属性
  6. mocker_class_spec = mocker.patch('api_testcases.mock_test.mock_request', spec=Foo)
  7. logger.info(mocker_class_spec._num)

if name == “main“: pytest.main()

“”” ============================= test session starts ============================== platform darwin — Python 3.7.7, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 rootdir: /Users/zaygee/pytest_test, configfile: pytest.ini plugins: allure-pytest-2.9.42, mock-3.6.1, xdist-2.2.1, forked-1.3.0 collected 1 item

test_mock_1.py::test_mocker_spec ———————————————— live log call ————————————————- 2021-08-29 22:47:02 INFO 2021-08-29 22:47:02 INFO PASSED [100%]

============================== 1 passed in 0.02s =============================== “””

  1. <a name="oGUkf"></a>
  2. ### 断言
  3. 1. **assert_called**:检查mock对象至少被调用一次
  4. 1. **assert_not_called**:检查mock对象没有被调用
  5. 1. **assert_called_once**:检查mock对象只被调用一次
  6. 1. **assert_called_with:**检查mock对象的参数是否正确
  7. 1. **assert_called_once_with**:检查mock对象只被调用一次
  8. 1. **assert_any_call**:检查mock对象在全局过程中是否调用了该方法
  9. ```python
  10. import pytest
  11. from api_testcases.mock_test import invoke_mock_request, mock_request
  12. from common import logger
  13. URL = 'https://docs.cypress.io/'
  14. def test_mock_request(mocker):
  15. mocker_inst = mocker.patch('api_testcases.mock_test.mock_request', return_value=mock_request, name='test mock')
  16. assert invoke_mock_request(URL) == mocker_inst.return_value
  17. # 断言至少被调用一次
  18. mocker_inst.assert_called()
  19. # 断言只被调用一次
  20. mocker_inst.assert_called_once()
  21. # 断言mock对象的参数是否正确
  22. mocker_inst.assert_called_with(URL)
  23. # 断言mock对象是否没有被调用
  24. # mocker_inst.assert_not_called()
  25. mocker_inst.assert_called_once_with(URL)
  26. # 断言对象在全局过程中是否调用了该方法
  27. mocker_inst.assert_any_call(URL)
  28. logger.info(mocker_inst)
  29. if __name__ == "__main__":
  30. pytest.main()
  31. """
  32. ============================= test session starts ==============================
  33. platform darwin -- Python 3.7.7, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
  34. rootdir: /Users/zaygee/pytest_test, configfile: pytest.ini
  35. plugins: allure-pytest-2.9.42, mock-3.6.1, xdist-2.2.1, forked-1.3.0
  36. collected 1 item
  37. test_mock_1.py::test_mock_request
  38. -------------------------------- live log call ---------------------------------
  39. 2021-08-29 22:51:22 INFO <MagicMock name='test mock' id='140218070657296'>
  40. PASSED [100%]
  41. ============================== 1 passed in 0.01s ===============================
  42. """
  1. # mock_test.py
  2. import requests
  3. def mock_request(url):
  4. return requests.get(url=url).status_code
  5. def invoke_mock_request(url):
  6. return mock_request(url)
  7. # test_mock_1.py
  8. import mock
  9. import pytest
  10. from mock import Mock
  11. from api_testcases.mock_test import invoke_mock_request, mock_request
  12. def test_mock_request():
  13. with mock.patch('api_testcases.mock_test.mock_request', return_value=200, side_effect=mock_request) as mock_foo:
  14. assert invoke_mock_request(URL) == mock_foo.return_value
  15. @mock.patch('api_testcases.mock_test.mock_request', return_value=300)
  16. def test_mock_request1(mock_request):
  17. assert invoke_mock_request(URL) == mock_request.return_value
  18. if __name__ == "__main__":
  19. pytest.main()
  20. """
  21. ============================= test session starts ==============================
  22. platform darwin -- Python 3.7.7, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
  23. rootdir: /Users/zaygee/pytest_test, configfile: pytest.ini
  24. plugins: allure-pytest-2.9.42, mock-3.6.1, xdist-2.2.1, forked-1.3.0
  25. collected 2 items
  26. test_mock_1.py::test_mock_request PASSED [ 50%]
  27. test_mock_1.py::test_mock_request1 PASSED [100%]
  28. ============================== 2 passed in 0.63s ===============================
  29. """

mock管理方法

  1. attach_mock:将一个mock对象添加到另一个mock对象中
  2. configure_mock:修改mock对象的return_value值 ```python import pytest from api_testcases.mock_test import invoke_mock_request, mock_request, TestMock1, TestMock2 from common import logger

def test_mock_management(mocker): mocker_attach_1 = mocker.patch(‘api_testcases.mock_test.TestMock1’) mocker_attach_2 = mocker.patch(‘api_testcases.mock_test.TestMock2’) logger.info(mocker_attach_1._value1) logger.info(mocker_attach_1.func1) logger.info(mocker_attach_2)

  1. # 调用attach_mock方法,将mocker_attach_2 添加到mocker_attach_1中,重命名为mock_attach
  2. mocker_attach_1.attach_mock(mocker_attach_2, 'mock_attach')
  3. logger.info(mocker_attach_1.func1)
  4. logger.info(mocker_attach_1.mock_attach.func2)
  5. # configure_mock方法,修改mock对象的return_value值
  6. mocker_attach_3 = mocker.patch('api_testcases.mock_test.mock_request')
  7. mocker_attach_3.configure_mock(return_value=100)
  8. assert invoke_mock_request(URL) == 100

if name == “main“: pytest.main()

“”” ============================= test session starts ============================== platform darwin — Python 3.7.7, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 rootdir: /Users/zaygee/pytest_test, configfile: pytest.ini plugins: allure-pytest-2.9.42, mock-3.6.1, xdist-2.2.1, forked-1.3.0 collected 1 item

test_mock_1.py::test_mock_management ———————————————— live log call ————————————————- 2021-08-29 23:00:40 INFO 2021-08-29 23:00:40 INFO 2021-08-29 23:00:40 INFO 2021-08-29 23:00:40 INFO 2021-08-29 23:00:40 INFO PASSED [100%]

============================== 1 passed in 0.01s =============================== “”” ```

  1. mock_add_spec:给mock对象添加新属性
  2. reset_mock:重置mock对象

    mock统计

  3. called:Boolean:跟踪mock对象任意调用的访问器

  4. call_count:Int:mock对象被调用的次数
  5. call_args:Tuple:获取最近调用使用的参数
  6. method_calls:List:测试mock对象的调用方法列表
  7. mock_calls:List:显示调用和方法调用
  8. call_args_list:List:获取最近调用使用的参数列表