python 单元测试 mock patch

简介: python 单元测试 mock patch

单元测试的概念

随着软件开发规模的不断变大,代码体积的膨胀,路径覆盖,以及整体测试会变得十分困难

所以错误定位,以及 代码单元可靠 十分必要。


单元测试,简单讲,就是对 一部分代码编写测试用例,以确保被测试的代码单元代码的可靠性。

下边举一个很简单的单元测试例子

待测试单元(模块)


my_math.py

很简单的模块,他只包含了,加法,乘法,阶乘

#!/usr/bin/python
# -*- coding:utf-8 -*-
'''
@File    :   my_math.py
@Time    :   2020/12/24 16:38:24
@Author  :   lmk
@Version :   1.0
'''
def my_add(a, b):
    return a+b
def my_multiply(a, b):
    return a*b
def my_factorial(a, b):
    return a**b
if __name__ == '__main__':
    pass

编写一个 加法 测试单元

#!/usr/bin/python
# -*- coding:utf-8 -*-
'''
@File    :   test_my_math.py
@Time    :   2020/12/24 16:26:49
@Author  :   lmk
@Version :   1.0
'''
from testtools import TestCase
import my_math
class Test_my_math(TestCase):
    def setUp(self):
        super(Test_my_math, self).setUp()
        print("this is set_up")
    def test_my_add_case_1(self):
        self.assertEqual(6, my_math.my_add(1, 5))
    def test_my_add_case_2(self):
        self.assertEqual(7, my_math.my_add(1, 5))
if __name__ == '__main__':
    pass

执行这个测试单元

python3 -m testtools.run test_my_math.py
RuntimeWarning: 'testtools.run' found in sys.modules after import of package 'testtools', but prior to execution of 'testtools.run'; this may result in unpredictable behaviour
  warn(RuntimeWarning(msg))
Tests running...
this is set_up
this is set_up
======================================================================
FAIL: test_my_math.Test_my_math.test_my_add_case_2
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/lmk/codes/learn_testtools/test_my_math.py", line 25, in test_my_add_case_2
    self.assertEqual(7, my_math.my_add(1, 5))
  File "/home/lmk/.local/lib/python3.6/site-packages/testtools/testcase.py", line 415, in assertEqual
    self.assertThat(observed, matcher, message)
  File "/home/lmk/.local/lib/python3.6/site-packages/testtools/testcase.py", line 502, in assertThat
    raise mismatch_error
testtools.matchers._impl.MismatchError: 7 != 6
Ran 2 tests in 0.002s
FAILED (failures=1)


Ran 2 tests in 0.002s

FAILED (failures=1)


输出结果表明 两项 测试 有一项失败了

assertEqual 断言函数,接受三个参数


def assertEqual(self, expected, observed, message=’’):


expected 是 逻辑上期待 的正确结果

observed 是 代码实际 的运行结果

message 是 额外的 错误信息

测试命令的其他可选项

python3 -m testtools.run -h
  -h, --help            show this help message and exit
  -v, --verbose         Verbose output
  -q, --quiet           Quiet output
  --locals              Show local variables in tracebacks
  -f, --failfast        Stop on first fail or error
  -c, --catch           Catch ctrl-C and display results so far
  -b, --buffer          Buffer stdout and stderr during tests
  -l, --list            List tests rather than executing them
  --load-list LOAD_LIST
                        Specifies a file containing test ids, only tests
                        matching those ids are executed
  -s START, --start-directory START
                        Directory to start discovery ('.' default)
  -p PATTERN, --pattern PATTERN
                        Pattern to match tests ('test*.py' default)
  -t TOP, --top-level-directory TOP
                        Top level directory of project (defaults to start
                        directory)

进阶1 - mock 模拟测试


在开发工作中,难免有一些函数,项目是 并行开发的。

这个func 依赖其他项目的 输出。

那么此时想要 进行 单元测试。屏蔽外部干扰。


如果不进行模拟而是进行,真正的依赖,那么很有可能导致错误的产生。


上游错误,导致下游所有测试失败。

多个错误发生了叠加,使得错误更难被追踪。

所以我们尽量采用 mock 来屏蔽外部的干扰,让程序得到预期的输入

在 Test_my_math 添加 模拟 测试函数指定返回 固定值

添加一个@patch 装饰器 来 模拟函数返回值

@patch("my_math.my_add", new=Mock(return_value=7))
def test_my_add_case_3(self):
    res = my_math.my_add(1, 5)
    self.assertEqual(7, res)
python3 -m testtools.run test_my_math.py 
Ran 2 tests in 0.002s
OK


指定 模拟函数 多次调用的 不同的返回值

from cinder import test
from cinder.volume import ceph_api
from cinder.tests.unit.volume.volume_constant import val
import mock
class TestCephApi(test.TestCase):
    def setUp(self):
        super(TestCephApi, self).setUp()
        self.api = ceph_api.API()
        self.context = None
    # return list when then input is right
    @mock.patch("cinder.volume.ceph_api.API._handle_ceph_cmd", mock.Mock(side_effect = [[_, val.RIGHT_POOL_INFO_OUTBUF, _], [_, val.RIGHT_POOL_DF_OUTBUF, _]]))
    def test_get_all_pools_with_right_input(self):
        res = self.api.get_all_pools(self.context)
        self.assertIsInstance(res, list)
    # return  AttributeError when input is err
    @mock.patch("cinder.volume.ceph_api.API._handle_ceph_cmd", mock.Mock(side_effect = [[_, val.ERR_POOL_INFO_OUTBUF, _], [_, val.ERR_RIGHT_POOL_DF_OUTBUF, _]]))
    def test_get_all_pools_with_err_input(self):
        self.assertRaises(AttributeError, self.api.get_all_pools, self.context)
    # return dict when then input is right
    @mock.patch("cinder.volume.ceph_api.API.get_all_mons", mock.Mock(side_effect = [""]))
    @mock.patch("cinder.volume.ceph_api.API.get_all_pools", mock.Mock(side_effect = [""]))
    @mock.patch("cinder.volume.ceph_api.API._handle_ceph_cmd", mock.Mock(side_effect = [[_, val.RIGHT_POOL_STATUS_OUTBUF, _]]))
    def test_get_all_status_with_right_input(self):
        res = self.api.get_all_status(self.context)
        self.assertIsInstance(res, dict)
    # return keyerr when input is err
    @mock.patch("cinder.volume.ceph_api.API.get_all_mons", mock.Mock(side_effect = [""]))
    @mock.patch("cinder.volume.ceph_api.API.get_all_pools", mock.Mock(side_effect = [""]))
    @mock.patch("cinder.volume.ceph_api.API._handle_ceph_cmd", mock.Mock(side_effect = [[_, val.ERR_POOL_STATUS_OUTBUF, _]]))
    def test_get_all_status_with_err_input(self):
        self.assertRaises(KeyError, self.api.get_all_status, self.context)


side_effect 拓展用法,采用函数替换,patch 目标函数

如果希望更加动态的 指定 mock 返回值。

可以考虑采用一个 简单函数 来 mock 原有函数。

mock = Mock(return_value=3)
def side_effect_func(*args, **kwargs):
    return DEFAULT
mock.side_effect = side_effect_func
mock()






相关文章
|
10天前
|
Web App开发 JSON 测试技术
Python在自动化测试中的角色
本文探讨了Python在自动化测试中的关键作用,强调其语法简洁、丰富的库和框架(如Selenium和Appium)、跨平台兼容性和可扩展性。通过示例展示了Python结合Selenium进行Web自动化测试以及使用requests库进行API自动化测试的应用,指出Python在自动化测试领域的日益重要性。
|
14天前
|
区块链 Python
最新用Python从零开始创建区块链_基于python做区块链,哔哩哔哩测试面试题
最新用Python从零开始创建区块链_基于python做区块链,哔哩哔哩测试面试题
|
15天前
|
数据采集 JSON 数据格式
2024年最新【python基础教程】常用内置模块(1),2024年最新头条测试面试
2024年最新【python基础教程】常用内置模块(1),2024年最新头条测试面试
|
18天前
|
敏捷开发 Java Devops
深入理解与应用软件测试中的Mock技术
【5月更文挑战第17天】 在现代软件开发过程中,单元测试是保证代码质量的重要手段。然而,对于依赖外部系统或服务的功能,如何有效进行单元测试一直是一大挑战。Mock技术的引入为这一难题提供了解决方案。本文将详细探讨Mock技术的概念、应用场景以及在实际软件测试中的优势和局限性,同时提供一些最佳实践和常见框架的使用指南。
|
18天前
|
Java 测试技术 数据库
深入理解与应用软件测试中的Mock对象
【5月更文挑战第17天】在软件开发过程中,单元测试是确保代码质量的重要环节。本文将深入探讨Mock对象在软件测试中的应用,分析其对提升测试效率和准确性的重要性。通过具体案例,我们将了解如何创建和使用Mock对象,以及它们如何帮助开发者隔离依赖,模拟外部系统行为,从而使得单元测试更加高效和可靠。
|
20天前
|
前端开发 Java 测试技术
selenium+python自动化测试--登录
selenium+python自动化测试--登录
19 2
|
20天前
|
存储 人工智能 测试技术
python自动化测试实战 —— CSDN的Web页面自动化测试
python自动化测试实战 —— CSDN的Web页面自动化测试
|
20天前
|
Web App开发 设计模式 测试技术
python自动化测试实战 —— 自动化测试框架的实例
python自动化测试实战 —— 自动化测试框架的实例
|
20天前
|
监控 数据可视化 IDE
python自动化测试实战 —— 单元测试框架
python自动化测试实战 —— 单元测试框架
|
20天前
|
Web App开发 JavaScript 测试技术
python自动化测试实战 —— WebDriver API的使用
python自动化测试实战 —— WebDriver API的使用