Python - 测试线程应用程序



在本章中,我们将学习 thread 应用程序的测试。我们还将了解测试的重要性。

为什么要测试?

在我们深入讨论测试的重要性之前,我们需要了解什么是测试。一般来说,测试是一种找出某物运行情况的技术。另一方面,特别是如果我们谈论计算机程序或软件,那么测试是访问软件程序功能的技术。

在本节中,我们将讨论软件测试的重要性。在软件开发中,在向客户发布软件之前必须进行仔细检查。这就是为什么由经验丰富的测试团队测试软件非常重要的原因。请考虑以下几点以了解软件测试的重要性 -

软件质量的提高

当然,没有公司愿意提供低质量的软件,也没有客户愿意购买低质量的软件。测试通过查找和修复其中的错误来提高软件的质量。

客户满意

任何企业最重要的部分是客户的满意度。通过提供无错误和高质量的软件,公司可以实现客户满意度。

减少新功能的影响

假设我们做了一个 10000 行的软件系统,我们需要增加一个新功能,那么开发团队会担心这个新功能对整个软件的影响。在这里,测试也起着至关重要的作用,因为如果测试团队做了一套好的测试,那么它可以使我们免于任何潜在的灾难性中断。

用户体验

任何企业的另一个最重要的部分是该产品的用户体验。只有测试才能确保最终用户发现产品使用简单易行。

削减开支

测试可以通过在开发的测试阶段发现并修复错误而不是在交付后修复来降低软件的总成本。如果软件交付后出现重大错误,那么它将增加其有形成本,例如费用和无形成本,例如客户不满、公司的负面声誉等。

测试什么?

始终建议对要测试的内容有适当的了解。在本节中,我们将首先了解测试人员在测试任何软件时的主要动机。应避免代码覆盖率,即测试套件在测试时命中多少行代码。这是因为,在测试时,只关注代码行数不会给我们的系统增加真正的价值。可能仍然存在一些错误,即使在部署之后,这些错误也会在稍后阶段反映出来。

请考虑以下与测试内容相关的要点 -

  • 我们需要专注于测试代码的功能,而不是代码覆盖率。
  • 我们需要先测试代码中最重要的部分,然后再测试代码中不太重要的部分。它肯定会节省时间。
  • 测试人员必须具有多种不同的测试,这些测试可以将软件推向极限。

测试并发软件程序的方法

由于能够利用多核架构的真正功能,并发软件系统正在取代顺序系统。近年来,并发系统程序被用于从手机到洗衣机、从汽车到飞机等所有领域。我们需要更加小心地测试并发软件程序,因为如果我们向已经存在 bug 的单线程应用程序添加了多个线程,那么我们最终会得到多个 bug。

并发软件程序的测试技术广泛集中在选择暴露潜在有害模式(如竞争条件、死锁和违反原子性)的交错上。以下是测试并发软件程序的两种方法 -

系统探索

这种方法旨在尽可能广泛地探索交错的空间。这些方法可以采用蛮力技术,而其他方法可以采用部分降阶技术或启发式技术来探索交错的空间。

属性驱动

属性驱动方法依赖于以下观察结果:并发错误更有可能发生在公开特定属性(如可疑内存访问模式)的交错下。不同的属性驱动方法针对不同的错误,如争用条件、死锁和违反原子性,这进一步取决于一个或其他特定属性。

测试策略

测试策略也称为测试方法。该策略定义了如何进行测试。测试方法有两种技术 -

积极

一种尽早启动测试设计流程的方法,以便在创建构建之前发现并修复缺陷。

反应性的

在开发过程完成之前不开始测试的方法。

在 python 程序上应用任何测试策略或方法之前,我们必须对软件程序可能存在的错误类型有一个基本的了解。错误如下 -

语法错误

在程序开发过程中,可能会有许多小错误。这些错误主要是由于键入错误造成的。例如,缺少冒号或关键字拼写错误等。此类错误是由于程序语法错误而不是逻辑错误造成的。因此,这些错误称为语法错误。

语义错误

语义错误也称为逻辑错误。如果软件程序中存在逻辑或语义错误,则该语句将正确编译和运行,但由于逻辑不正确,它不会给出所需的输出。

单元测试

这是测试 python 程序最常用的测试策略之一。此策略用于测试代码的单元或组件。我们所说的单元或组件是指代码的类或函数。单元测试通过测试“小”单元来简化大型编程系统的测试。借助上述概念,单元测试可以定义为一种方法,其中测试源代码的各个单元以确定它们是否返回所需的输出。

在后续部分中,我们将了解用于单元测试的不同 Python 模块。

unittest 模块

用于单元测试的第一个模块是 unittest 模块。它受到 JUnit 的启发,默认包含在 Python3.6 中。它支持测试自动化、共享测试的设置和关闭代码、将测试聚合到集合中以及测试独立于报告框架。

以下是 unittest 模块支持的一些重要概念

文本夹具

它用于设置测试,以便它可以在开始测试之前运行,并在测试完成后关闭。它可能涉及在开始测试之前创建所需的临时数据库、目录等。

测试用例

测试用例检查所需的响应是否来自特定的 Importing 集。unittest 模块包括一个名为 TestCase 的基类,可用于创建新的测试用例。默认情况下,它包括两种方法 -

  • setUp() − 在执行测试夹具之前设置它的钩子方法。在调用已实现的测试方法之前调用此函数。
  • tearDown() − 一个钩子方法,用于在运行类中的所有测试后解构类夹具。

测试套件

它是测试套件和/或测试用例的集合。

测试运行程序

它控制测试用例或套装的运行,并将结果提供给用户。它可以使用 GUI 或简单的文本界面来提供结果。

以下 Python 程序使用 unittest 模块测试名为 Fibonacci 的模块。该程序有助于计算数字的斐波那契数列。在此示例中,我们创建了一个名为 Fibo_test 的类,以使用不同的方法定义测试用例。这些方法继承自 unittest。TestCase 的默认情况下,我们使用两种方法 – setUp() 和 tearDown()。我们还定义了 testfibocal 方法。测试的名称必须以字母 test 开头。在最后一个块中,unittest.main() 为测试脚本提供了一个命令行界面。


import unittest
def fibonacci(n):
	 	a, b = 0, 1
	 	for i in range(n):
	 	a, b = b, a + b
	 	return a
class Fibo_Test(unittest.TestCase):
	 	def setUp(self):
	 	print("This is run before our tests would be executed")
	 	def tearDown(self):
	 	print("This is run after the completion of execution of our tests")

	 	def testfibocal(self):
	 	self.assertEqual(fib(0), 0)
	 	self.assertEqual(fib(1), 1)
	 	self.assertEqual(fib(5), 5)
	 	self.assertEqual(fib(10), 55)
	 	self.assertEqual(fib(20), 6765)

if __name__ == "__main__":
	 	unittest.main()

从命令行运行时,上述脚本会生成如下所示的输出 -

This runs before our tests would be executed.
This runs after the completion of execution of our tests.
.
----------------------------------------------------------------------
Ran 1 test in 0.006s
OK

现在,为了更清楚,我们正在更改有助于定义斐波那契模块的代码。

以以下代码块为例 -


def fibonacci(n):
	 	a, b = 0, 1
	 	for i in range(n):
	 	a, b = b, a + b
	 	return a

对代码块进行了一些更改,如下所示 -


def fibonacci(n):
	 	a, b = 1, 1
	 	for i in range(n):
	 	a, b = b, a + b
	 	return a

现在,在使用更改的代码运行脚本后,我们将获得以下输出 -

This runs before our tests would be executed.
This runs after the completion of execution of our tests.
F
======================================================================
FAIL: testCalculation (__main__.Fibo_Test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "unitg.py", line 15, in testCalculation
self.assertEqual(fib(0), 0)
AssertionError: 1 != 0
----------------------------------------------------------------------
Ran 1 test in 0.007s

FAILED (failures = 1)

上面的输出显示模块未能提供所需的输出。

Docktest 模块

docktest 模块还有助于单元测试。它还预打包了 python。它比 unittest 模块更容易使用。unittest 模块更适合于复杂的测试。要使用 doctest 模块,我们需要导入它。相应函数的文档字符串必须具有交互式 python 会话及其输出。

如果我们的代码中一切正常,那么 docktest 模块将不会有输出;否则,它将提供输出。

以下 Python 示例使用 docktest 模块测试名为 Fibonacci 的模块,该模块有助于计算数字的 Fibonacci 级数。


import doctest
def fibonacci(n):
	 	"""
	 	Calculates the Fibonacci number

	 	>>> fibonacci(0)
	 	0
	 	>>> fibonacci(1)
	 	1
	 	>>> fibonacci(10)
	 	55
	 	>>> fibonacci(20)
	 	6765
	 	>>>

	 	"""
	 	a, b = 1, 1
	 	for i in range(n):
	 	a, b = b, a + b
	 	return a
	 	 	 if __name__ == "__main__":
	 	doctest.testmod()

我们可以看到名为 fib 的相应函数的文档字符串具有交互式 python 会话以及输出。如果我们的代码很好,那么 doctest 模块就不会有输出。但是要了解它是如何工作的,我们可以使用 –v 选项运行它。


(base) D:\ProgramData>python dock_test.py -v
Trying:
	 	fibonacci(0)
Expecting:
	 	0
ok
Trying:
	 	fibonacci(1)
Expecting:
	 	1
ok
Trying:
	 	fibonacci(10)
Expecting:
	 	55
ok
Trying:
	 	fibonacci(20)
Expecting:
	 	6765
ok
1 items had no tests:
	 	__main__
1 items passed all tests:
4 tests in __main__.fibonacci
4 tests in 2 items.
4 passed and 0 failed.
Test passed.

现在,我们将更改有助于定义 Fibonacci 模块的代码

以下代码块为例 -


def fibonacci(n):
	 	a, b = 0, 1
	 	for i in range(n):
	 	a, b = b, a + b
	 	return a

以下代码块有助于进行更改 -


def fibonacci(n):
	 	a, b = 1, 1
	 	for i in range(n):
	 	a, b = b, a + b
	 	return a

即使没有 –v 选项,运行脚本后,使用更改的代码,我们将获得如下所示的输出。

输出

(base) D:\ProgramData>python dock_test.py
**********************************************************************
File "unitg.py", line 6, in __main__.fibonacci
Failed example:
fibonacci(0)
Expected:
0
Got:
1
**********************************************************************
File "unitg.py", line 10, in __main__.fibonacci
Failed example:
fibonacci(10)
Expected:
55
Got:
89
**********************************************************************
File "unitg.py", line 12, in __main__.fibonacci
Failed example:
fibonacci(20)
Expected:
6765
Got:
10946
**********************************************************************
1 items had failures:
3 of 4 in __main__.fibonacci
***Test Failed*** 3 failures.

我们可以在上面的输出中看到三个测试失败。