Python 中的参数化单元测试
单元测试是维护软件质量的一种强大工具。 软件单元测试是对一段代码进行的一系列检查,以确保软件的开发符合软件设计规范,并按照最终用户的预期行为或响应。
在 Python 中,我们可以使用参数化单元测试为每个项目或测试用例生成一个测试。 本文将探讨 Python 的参数化单元测试。
Python 中参数化单元测试的目的
当开发人员编写单元测试时,他们通常采用一种测试一种情况的方法。 然后将最相似或相关的测试组合成一个套件。
查看下面代码中的测试套件:
class TestSuite(TestCase):
def test_first_case(self):
assert example_test()
def test_second_case(self):
assert more_example_tests()
def test_third_case(self):
assert another_example_test()
通过像这样的套件进行测试意味着每个测试用例都必须经历一系列自定义阶段的准备、执行和最后的断言。 如果这些测试用例中的每一个都相似,那么生成的套件将是一团乱七八糟的重复或冗余代码,这在软件开发人员的世界中无异于诅咒。
这些套件还会导致代码库庞大,在进行更改时极难维护(这是预料之中的)。 为了解决这个问题,我们在 Python 中得到了动态或参数化单元测试的祝福,使我们能够为多个案例生成单一测试。
Python 中参数化单元测试的示例
让我们深入研究一个示例测试场景或方法,我们可以以此为基础来理解 Python 中的参数化单元测试以及它如何使我们作为软件开发人员的生活变得更加轻松。
下面是我们要测试的一个简单函数:
def compute(a, b):
return (a + b) / (a * b)
现在,就像任何测试一样,我们知道我们需要将多个输入应用到上面的函数以测试它是否以所需的方式运行。 为了更详细地指定测试参数,我们需要根据以下参数测试该方法:
- 正整数
- 负整数
- 长整数
- 正则整数
- 浮点数
- 其中一个或两个数字为零
- 一个或两个参数未定义
- 一个或两个参数是字符串或其他类型的对象
如果要使用每种情况一个测试的方法进行测试,我们将为单行方法编写一长串重复代码。 您可以想象,对于基于涉及循环和条件的多行代码的方法来说,这是多么忙碌和乏味。
通过参数化,我们只需要这样做:
def test_compute(self, a, b, expected, raises=None):
if raises is not None:
with self.assertRaises(raises):
compute(a, b)
else:
assert compute(a, b) == expected
这样,我们需要准备一个参数列表,以最好地测试计算方法的所有可能性。 参数列表可以是我们想要的那么长,也可以只是我们需要测试的案例的集合。
以下是可以传递到上面的单元测试中的参数列表的示例。
代码的输出:
a | b | expected | raises
------------+-----+----------+-------
-2 | 2 | 0 |
0 | 2 | | ZeroDivisionError
2 | 2 | 1 |
0.5 | 0.4 | 4.5 |
None | 2 | | TypeError
"10" | "1" | | TypeError
3000000000L | 2 | 0.5 |
可以看出,这个列表和上面的参数化单元测试使我们能够更有效地测试可以传递给 compute() 方法的参数的各种场景。 它还使记录不同的结果变得更加容易。
Python 中参数化单元测试的好处
编写定期的单元测试可能是高度重复的、详尽的、耗时的和伤脑筋的,尤其是当我们希望测试遍历每个软件场景并确保一切都符合标准时。
在 Python 中使用参数化单元测试意味着我们作为开发人员不必担心编写数百行代码来测试正在开发的软件中可能出现的各种场景以保持其质量。 我们只需要一个测试来测试所有需要测试的场景。
这意味着测试代码库将始终易于维护,几乎没有重复,从而产生高效的测试用例和节省时间的结果。
此外,参数化单元测试迫使相关开发人员更清楚、更明确地思考进入该方法的所有可能输入。 它有助于跟踪边缘情况,例如上面示例中的大整数或不一致的输入类型,以及任何错误情况,例如未定义的输入。
该测试自然也迫使开发人员更多地考虑如何处理边缘情况,而不是仅仅考虑可能破坏其代码的输入类型。 它通过迫使我们预测函数在特定情况组合下的预期功能来帮助保持代码的质量,并导致针对所面临的任何问题开发概念和有效的解决方案。
更重要的是,如果我们决定使用更详尽或更广泛的参数列表来测试我们的方法,我们最终可能会得到测试用例的结果和解决方案,我们最初认为这些测试用例太琐碎而无法为其编写测试用例。 然而,有了我们可以使用的参数化测试,我们只需要输入我们想要测试的组合,看看代码如何响应。
支持参数化单元测试的 Python 库
Python 通过参数化库让我们的生活更轻松,这使得测试方法的开发变得简单明了。 我们所要做的就是导入参数化并通过测试套件中我们的方法中的参数化装饰器传递我们想要测试的参数,如下所示:
from parameterized import parameterized
class TestSuite(TestCase):
@parameterized.expand([
("test_1", 0, 0, 0),
("test_2", 0, 1, 1)
])
def test_my_feature(self, name, in_1, in_2, expected):
assert my_feature(in_1, in_2) == expected
另一种方法是创建一个包含所有参数列表的 .csv 文件。 然后,我们将它传递给装饰器进行测试,如下所示:
def load_test_cases():
return load_from_csv("my_feature_parameters.csv")
class TestSuite(TestCase):
@parameterized.expand(load_test_cases)
def test_my_feature(self, name, in_1, in_2, expected):
assert my_feature(in_1, in_2) == expected
我们已经涵盖了从为什么需要使用动态(参数化)单元测试到实现它的不同方法及其在软件开发生命周期中的好处的所有内容。 我们希望本文有助于您理解如何在 Python 中生成单元测试。
相关文章
Python Unittest 和 Pytest
发布时间:2023/06/22 浏览次数:105 分类:Python
-
这篇文章的主要目的是讨论Python中两个最常用的单元测试框架unittest和pytest,它们的优缺点以及在何时选择哪个框架。
Python 模拟类属性
发布时间:2023/06/22 浏览次数:161 分类:Python
-
本文的主要目的是演示如何使用 python 单元测试模块 unittest 操作类属性以进行测试和调试。模拟类属性的原因
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,并介绍了使用该模块时的行为。