迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > Python >

Python 模拟类属性

作者:迹忆客 最近更新:2023/06/21 浏览次数:

本文的主要目的是演示如何使用 python 单元测试模块 unittest 操作类属性以进行测试和调试。


模拟类属性的原因

测试开发的代码是否存在错误、错误和极端情况是开发应用程序时最重要的方面之一,尤其是当应用程序面向多个用户时。

使用内置的Python模块unittest,我们可以执行测试用例来测试代码的完整性。 需要严格测试的最常见元素之一是类属性。

类属性可以处理随机输入以防止意外行为。

考虑以下代码:

class Calculate:
    value = 22 # Needs to be tested for different data types

    def Process(self): # An example method
        pass

考虑一个名为 Calculate 的类,它包含一个名为 value 的属性和一个名为 Process 的方法。 字典存储在值中,稍后根据需求和数据类型对其进行处理。

为确保该属性几乎可以存储任何类型的字典并无错误地处理,必须测试该属性以确保实现无错误且不需要修改。


模拟类属性的可能解决方案

我们可以通过两种方式模拟类属性; 使用 PropertyMock 和不使用 PropertyMock。 让我们使用示例代码在下面学习它们中的每一个。

使用 PropertyMock 模拟类属性

要模拟属性,我们可以使用 PropertyMock,主要用作属性的模拟或类的描述符。

值得注意的是,PropertyMock 提供了 __get____set__ 方法来更改获取属性后的返回值。

考虑以下代码:

import unittest
from unittest.mock import patch
from unittest.mock import MagicMock, PropertyMock

class Calculate:
    value = 22 # Needs to be tested for different data types

    def Process(self): # An example method
        pass

class Test(unittest.TestCase):
    @patch.object(Calculate, 'value', new_callable=PropertyMock)

    def test_method(self, mocked_attrib):
        mocked_attrib.return_value = 1
        self.assertEqual(Calculate().value, 1) # Will pass without any complaints
        print("First Assertion Passed!")

        self.assertEqual(Calculate().value, 22) # Will throw an assertion
        print("Second Assertion Passed!")

if __name__ == '__main__':
    Test().test_method()

输出:

First Assertion Passed!
Traceback (most recent call last):
  File "d:\Python Articles\a.py", line 24, in <module>
    Test().test_method()
  File "C:\Program Files\Python310\lib\unittest\mock.py", line 1369, in patched
    return func(*newargs, **newkeywargs)
  File "d:\Python Articles\a.py", line 20, in test_method
    self.assertEqual(Calculate().value, 22) # Will throw an assertion 
  File "C:\Program Files\Python310\lib\unittest\case.py", line 845, in assertEqual
    assertion_func(first, second, msg=msg)
  File "C:\Program Files\Python310\lib\unittest\case.py", line 838, in _baseAssertEqual
    raise self.failureException(msg)
AssertionError: 1 != 22

在解决方案中,创建了一个新方法test_method来修改Calculate.value的值。 值得注意的是,函数是用 patch.object 修饰的。

模块中的补丁装饰器有助于修补模块和类级属性。 为了使修补内容更加具体,我们使用 patch.object 而不是 patch 直接修补方法。

在装饰器中,首先传递类名Calculate,表示要修补的对象是Calculate的一部分,传递的属性值的名称。

最后一个参数是一个 PropertyMock 对象,我们通过传递不同的数字来覆盖 value 属性。

程序的总体流程如下:

  1. test_method 被调用。
  2. 类Calculate的值被修补,并分配了一个new_callable,一个PropertyMock的实例。
  3. 使用 return_value 属性用 1 覆盖 Calculate.value。
  4. 检查第一个断言,其中Calculate.value 必须等于1。
  5. 检查第二个断言,其中 Calculate.value 必须等于 22。

在不使用 PropertyMock 的情况下模拟类属性

我们也可以不使用 PropertyMock 来解决它。 只需对上述示例稍作修改。

考虑以下代码:

import unittest
from unittest.mock import patch

class Calculate:
    value = 22 # Needs to be tested for different data types

    def Process(self): # An example method
        pass

class Test(unittest.TestCase):
    @patch.object(Calculate, 'value', 1)

    def test_method(self):
        # Will pass without any complaints
        self.assertEqual(Calculate().value, 1)
        print("First Assertion Passed!")

        # Will throw an assertion because "Calculate.value" is now 1
        self.assertEqual(Calculate().value, 22)
        print("Second Assertion Passed!")

if __name__ == '__main__':
    Test().test_method()

输出:

First Assertion Passed!
Traceback (most recent call last):
  File "d:\Python Articles\a.py", line 23, in <module>
    Test().test_method()
  File "C:\Program Files\Python310\lib\unittest\mock.py", line 1369, in patched
    return func(*newargs, **newkeywargs)
  File "d:\Python Articles\a.py", line 19, in test_method
    self.assertEqual(Calculate().value, 22) # Will throw an assertion because "Calculate.value" is now 1
  File "C:\Program Files\Python310\lib\unittest\case.py", line 845, in assertEqual
    assertion_func(first, second, msg=msg)
  File "C:\Program Files\Python310\lib\unittest\case.py", line 838, in _baseAssertEqual
    raise self.failureException(msg)
AssertionError: 1 != 22

我们可以直接将希望存储到Calculate.value 中的值给出,而不是将PropertyMock 的实例传递给new_callable。


Python 模拟类构造函数

确保所有初始化变量按预期工作并且不会表现出意外行为。 还需要使用不同的输入来测试构造函数,以减少任何极端情况。

考虑以下代码:

class Calculate:
    num = 0
    dic = {}

    def __init__(self, number, dictt):
        self.num = number
        self.dic = dictt

    def Process(self): # An example method
        pass

假设我们要测试Calculate 类的构造函数。 为了确保属性按预期工作,我们必须修补构造函数并传递不同的输入以消除任何可能的错误。

我们该怎么做? 请参阅以下解决方案。

使用 patch.object 装饰器来修补构造函数

我们可以使用 patch.object 装饰器来修补构造函数。

import unittest
from unittest.mock import patch
from unittest.mock import MagicMock, PropertyMock

class Calculate:
    num = 0
    dic = {}

    def __init__(self):
        self.num = 1
        self.dic = {"11", 2}

    def Process(self): # An example method
        pass

class Test(unittest.TestCase):
    @patch.object(Calculate, '__new__')
    def test_method(self, mocked_calc):
        mocked_instance = MagicMock()
        mocked_instance.num = 10
        mocked_instance.dic = {"22" : 3}
        mocked_calc.return_value = mocked_instance

        self.assertEqual(Calculate().num, 10)
        self.assertEqual(Calculate().dic, {"22" : 3})

        print("First set of Asserts done!")

        self.assertEqual(Calculate().num, 1)
        self.assertEqual(Calculate().dic, {"11", 2})
        print("Second set of Asserts done!")

if __name__ == '__main__':
    Test().test_method()

输出:

The first set of Asserts is done!
Traceback (most recent call last):
  File "d:\Python Articles\a.py", line 37, in <module>
    Test().test_method()
  File "C:\Program Files\Python310\lib\unittest\mock.py", line 1369, in patched
    return func(*newargs, **newkeywargs)
  File "d:\Python Articles\a.py", line 32, in test_method
    self.assertEqual(Calculate().num, 1)
  File "C:\Program Files\Python310\lib\unittest\case.py", line 845, in assertEqual
    assertion_func(first, second, msg=msg)
  File "C:\Program Files\Python310\lib\unittest\case.py", line 838, in _baseAssertEqual
    raise self.failureException(msg)
AssertionError: 10 != 1

值得注意的是,我们没有修补 __init__,而是修补了 __new__

这是因为类的实例是在执行 __new__ 时创建的,而在 __init__ 中,只初始化了变量。 那么,既然我们需要创建一个新的模拟实例,为什么我们要修补 __new__ 而不是 __init__

上一篇:Python 单元测试设置

下一篇:没有了

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

Python 单元测试设置

发布时间:2023/06/22 浏览次数:127 分类:Python

在本文中,我们将讨论什么是单元测试和 Python 单元测试框架。 我们还讨论了如何使用 setUp() 函数进行单元测试以及示例。

Python rsync 同步

发布时间:2023/06/22 浏览次数:129 分类:Python

本文将探讨 rsync 以及我们如何从 Python 脚本中使用它。Python同步如上所述,rsync 是一个强大的工具

Python Deque Peek 介绍

发布时间:2023/06/22 浏览次数:198 分类:Python

本文演示了如何在 Python 中查看/检查双端队列(双端队列)前面的元素,而无需将它们从双端队列中删除。Python Deque Peek 概述

Python 中的异步请求

发布时间:2023/06/22 浏览次数:74 分类:Python

今天我们来学习一下异步请求; 这个讨论将引出代码示例,看看我们如何在 Python 中编写异步请求。Python 中的异步请求

Python - 等待异步函数完成

发布时间:2023/06/22 浏览次数:163 分类:Python

本文介绍如何创建异步函数并使用await 关键字中断进程。 我们还将学习如何在 Python 中使用任务而不是线程。

在 Python 中列出虚拟环境

发布时间:2023/06/21 浏览次数:149 分类:Python

在本文中,我们将讨论什么是 Python 中的虚拟环境以及列出它们的一些命令。虚拟环境是一个独立的环境,我们可以在其中安装库、包、脚本和Python解释器。

Python 中的 Urljoin 简介

发布时间:2023/06/21 浏览次数:178 分类:Python

本篇文章介绍了如何使用 Python 中的 urljoin() 模块形成 URL,并介绍了使用该模块时的行为。

Python 中并发方面的差异

发布时间:2023/06/21 浏览次数:68 分类:Python

本文将讨论如何在Python中实现并发以及其优点和缺点。线程和多线程 线程在Python中已经存在很长时间了。

Python 中从线程获取返回值

发布时间:2023/06/21 浏览次数:145 分类:Python

这篇文章首先讨论了线程的基础知识,并提供了一个在Python中启动线程的代码示例。然后,我们将讨论一个在线程中获取函数返回值的代码。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便