Python 中的单元测试:快速概述

在 SDLC 的不同阶段进行测试非常关键。 测试可以是单元测试、集成测试、负载测试、压力测试等。测试对于保证系统在不同场景和输入条件下的稳定性很重要。

这是太空任务所发生的事情,通过足够的单元测试和 linting(测量代码质量和遵守标准的过程)可以避免(希望)。 让人起鸡皮疙瘩,不是吗?

单元测试 毫无疑问,这是每个开发人员都应该具备的最重要的技能之一。 任何具有数千或数百万个移动部件的大型应用程序都无法手动测试回归。

单元测试 是一种完全自动化的测试最小代码段的方法,也称为单元。 这里的主要目标是在本地机器上而不是在生产环境中破坏代码。

单元测试在以下几个方面与传统的手动测试不同:

  1. 它是完全自动化的。 编写的测试用例经过编码并自动或手动运行(如本文所示)。 在工作中,人们可能会注意到构建或部署管道在合并和/或部署代码之前运行测试。
  2. 测试最小的代码单元。 最小的单元通常意味着一个方法或一个函数,但它也可以是一行代码。
  3. 它允许“测试驱动开发”,一种敏捷开发策略,在完成任何数量的代码之前编写测试,并在开发完成后检查测试是否通过。

单元测试的好处

提高代码质量

编写测试迫使我们创建易于测试的功能组件。 这种做法使代码模块化和可维护。

早期检测软件错误

没有代码是没有错误的,优秀的开发人员应该知道哪种情况会导致错误。 单元测试可以检测在手动测试软件时可能被认为很少见的场景,但是,在 Live 中,此类场景可能会更频繁地发生。

预先测试边缘案例场景

在将代码部署到实时环境中之前,可以很好地识别整数溢出、IndexOutOfBound 甚至 NullPointers 等情况。 我们还应该考虑到代码应该在某些情况下抛出错误,单元测试是测试这些错误是否真的被抛出的好方法。

降低成本和开发时间

编写大量的单元测试确实需要相当长的时间,但是,考虑到它们提供的好处,从长远来看,它们是有回报的。 在开发阶段早期没有发现的错误会被跳到测试和生产中,以便在调试、错误修复和部署上花费更多时间。

简化文档

单元测试本身就是开发人员代码的文档。 正在为其编写单元测试的每个类或文件都涵盖了所有不同的场景,阅读单元测试应该能够充分了解组件试图实现的目标。

强化部署和代码提交管道

可以设置部署管道以在部署系统之前甚至在部署之前运行单元测试,同时我们将代码提交给版本控制系统(例如 Git)。 这确保了部署不会失败,并且添加的任何新功能都不会破坏已经工作的功能。

单元测试 包裹

Python 带有 unittest 包,最初是受 JUnit 启发的。 但是,我们不需要安装任何软件包。 有一些重要的概念 单元测试 像在 Junit 中一样支持。

测试夹具

如果一个人来自 Java 和 Junit 背景,他们必须熟悉单元测试中使用的 setUp() 和 tearDown()。 在 python 中,测试装置做同样的事情。 它们可用于创建临时目录、数据库连接、伪造品、模拟等 设置() 并销毁这些对象和临时目录和连接 拆除().

测试用例

测试用例类似于我们为测试功能而创建的类。 它检查针对输入组合返回的响应。

测试套件

在为代码运行测试时,可能希望将多个测试组合在一个保护伞下,以便它们一起运行。 我们可以对测试用例和/或测试套件进行分组。

测试赛跑者

测试运行器具有编排测试执行的魔力。 在本文后面,您可能会注意到,呈现的结果可以是文本格式和/或图形界面。

理论够了!! 让我们做一些测试……

下表列出了一些最常用的断言方法,由 测试用例 类来检查和报告失败。

方法 检查那个
assertEqual(a, b) 一个 == b
assertNotEqual(a, b) 一个 != b
断言真(x) 布尔(X) 是真的
断言假(x) 布尔(X) 是假的
断言是(a,b) 一个 b
assertIsNot(a, b) 一个 不是 b
断言无(x) X 是无
assertIsNotNone(x) X 不是无
断言输入(a,b) 一个 b
assertNotIn(a, b) 一个 不是 在 b
断言IsInstance(a, b) 实例(一,乙)
assertNotIsInstance(a, b) 不是实例(一,乙)

一个基本的例子

让我们尝试实现一些测试 计算器.py

class Calculator:      def add(self, a: int, b: int) -> int:         return a + b  
    def sub(self, a: int, b: int) -> int:         return a - b      def mul(self, a: int, b: int) -> int:         return a * b      def div(self, a: int, b: int) -> float:         return a / b

Calculator_test.py 测试我们的计算器逻辑。 请注意,我们也考虑负面情况。

import unittest  from Calculator import Calculator  class CalculatorTest(unittest.TestCase):      def setUp(self) -> None:         super().setUp()         self.calculator = Calculator()      def test_add(self):         # Check add(5, 6) gives 11 or not         self.assertEqual(11, self.calculator.add(5, 6),                          "Testing Calculator.add()")      def test_sub(self):         # Check sub(5, 6) gives -1 or not         self.assertEqual(-1, self.calculator.sub(5, 6),                          "Testing Calculator.sub()")      def test_sub_fail(self):         # This test case will fail as sub(5, 6) is -1 not 10         self.assertEqual(10, self.calculator.sub(5, 6), "Testing Calculator.sub()")      def test_mul(self):         # Run single test multiple times with different parameters         # Parameter Source  params = [  {  'a': 5,  'b': 6,  'ret': 30  },  {  'a': 5,  'b': -10,  'ret': -50  },  {  'a': 0,  'b': 6,  'ret': 0  },  {  'a': 9,  'b': -6,  'ret': -54  },  ] 

对于参数中的参数:

self.assertEqual(param['ret'], self.calculator.mul(  param['a'], param['b']), "Testing Calculator.mul()")  def test_div(self):  # Check div(40, 2) gives 20 or not  self.assertEqual(20, self.calculator.div(  40, 2), "Testing Calculator.div()")  # Check div(20, 40) gives 0.5 or not  self.assertEqual(20/40, self.calculator.div(20, 40),  "Testing Calculator.div()")  # Check div(10, 3) gives 3.每日瀏覽3 or not (rounded upto 7 decimal places)  self.assertAlmostEqual(3.每日瀏覽3, self.calculator.div(10, 3),  msg="Testing Calculator.div()")  # Check whether Divide by 0 throws exception ZeroDivisionError  self.assertRaises(ZeroDivisionError, self.calculator.div, 20, 0)  if __name__ == "__main__":  unittest.main()

一个测试用例继承 单元测试.TestCase. 设置() 准备测试夹具并将在执行每个测试方法之前运行。 各个测试方法的名称需要以 测试_ 得到测试运行者的认可。
子测试() 上下文管理器用于区分测试方法体内的测试迭代。

我们测试的输出如下所示:

所有测试用例都按预期运行。

但是,如果您使用 IDE 之类的 皮查姆 或者 VSCode 然后是一个 GUI 测试运行器,它以图形方式显示成功和失败。

VSCode 打开测试文件,按 Shift + P 并选择 Python:运行当前测试文件