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()






相关文章
|
3月前
|
测试技术 开发者 Python
Python单元测试入门:3个核心断言方法,帮你快速定位代码bug
本文介绍Python单元测试基础,详解`unittest`框架中的三大核心断言方法:`assertEqual`验证值相等,`assertTrue`和`assertFalse`判断条件真假。通过实例演示其用法,帮助开发者自动化检测代码逻辑,提升测试效率与可靠性。
363 1
|
4月前
|
运维 Linux 开发者
Linux系统中使用Python的ping3库进行网络连通性测试
以上步骤展示了如何利用 Python 的 `ping3` 库来检测网络连通性,并且提供了基本错误处理方法以确保程序能够优雅地处理各种意外情形。通过简洁明快、易读易懂、实操性强等特点使得该方法非常适合开发者或系统管理员快速集成至自动化工具链之内进行日常运维任务之需求满足。
270 18
|
4月前
|
安全 测试技术 API
Python 单元测试详解
单元测试是Python开发中不可或缺的环节,能确保代码按预期运行、发现Bug、提升代码质量并支持安全重构。本文从基础概念讲起,逐步介绍Python单元测试的实践方法,涵盖unittest框架、pytest框架、断言使用、Mock技巧及测试覆盖率分析,助你全面掌握单元测试技能。
255 0
|
5月前
|
IDE 测试技术 API
python调试与测试
python调试与测试
|
5月前
|
人工智能 Java 测试技术
Java or Python?测试开发工程师如何选择合适的编程语言?
测试工程师如何选择编程语言?Java 还是 Python?多位资深专家分享建议:Python 入门简单、开发效率高,适合新手及自动化测试;Java 生态成熟,适合大型项目和平台开发。建议结合公司技术栈、个人基础及发展方向选择。长远来看,两者兼通更佳,同时关注 Go 等新兴语言。快速学习与实践才是关键。
|
6月前
|
测试技术 Python
Python测试报告生成:整合错误截图,重复用例执行策略,调整测试顺序及多断言机制。
如何组织这一切呢?你可以写一本名为“Python测试之道”的动作指南手册,或者创建一个包含测试策略、测试顺序、多断言机制的脚本库。只要你的测试剧本编写得足够独到,你的框架就会像一位执行任务的超级英雄,将任何潜伏于代码深处的错误无情地揪出来展现在光天化日之下。这些整理好的测试结果,不仅有利于团队协作,更像冒险故事中的精彩篇章,带给读者无尽的探索乐趣和深刻的思考。
170 10
|
6月前
|
测试技术 Python
Python接口自动化测试中Mock服务的实施。
总结一下,Mock服务在接口自动化测试中的应用,可以让我们拥有更高的灵活度。而Python的 `unittest.mock`库为我们提供强大的支持。只要我们正确使用Mock服务,那么在任何情况下,无论是接口是否可用,都可以进行准确有效的测试。这样,就大大提高了自动化测试的稳定性和可靠性。
290 0
|
9月前
|
存储 JSON API
Python测试淘宝店铺所有商品接口的详细指南
本文详细介绍如何使用Python测试淘宝店铺商品接口,涵盖环境搭建、API接入、签名生成、请求发送、数据解析与存储、异常处理等步骤。通过具体代码示例,帮助开发者轻松获取和分析淘宝店铺商品数据,适用于电商运营、市场分析等场景。遵守法规、注意调用频率限制及数据安全,确保应用的稳定性和合法性。
|
测试技术 Python
开发神技能 | Python Mock 的入门
Mock是什么 Mock这个词在英语中有模拟的这个意思,因此我们可以猜测出这个库的主要功能是模拟一些东西。准确的说,Mock是Python中一个用于支持单元测试的库,它的主要功能是使用mock对象替代掉指定的Python对象,以达到模拟对象的行为。
1167 0
|
测试技术 Python

热门文章

最新文章

推荐镜像

更多