测试线程应用程序
在本章中,我们将学习关于线程应用程序测试的内容。我们还将学习测试的重要性。
为什么要测试?
在我们深入讨论测试的重要性之前,我们需要了解什么是测试。一般来说,测试是一种找出某件事工作情况有多好的技术。另一方面,具体来说,如果我们谈论计算机程序或软件,那么测试就是访问软件程序功能的技术。
在本节中,我们将讨论软件测试的重要性。在软件开发中,在将软件发布给客户之前必须进行二次检查。这就是为什么由经验丰富的测试团队测试软件非常重要的原因。请考虑以下几点,以了解软件测试的重要性:
提高软件质量
当然,没有公司希望交付低质量的软件,也没有客户希望购买低质量的软件。测试通过查找和修复其中的错误来提高软件质量。
客户满意度
任何业务中最重要的部分是客户的满意度。通过提供无错误且高质量的软件,公司可以实现客户满意度。
减少新功能的影响
假设我们制作了一个 10000 行的软件系统,我们需要添加一个新功能,那么开发团队会担心此新功能对整个软件的影响。这里,测试也起着至关重要的作用,因为如果测试团队制作了一套良好的测试,那么它可以使我们免受任何潜在的灾难性故障。
用户体验
任何业务的另一个最重要的部分是该产品用户的体验。只有测试才能确保最终用户发现该产品简单易用。
降低成本
测试可以通过在软件开发的测试阶段查找和修复错误来降低软件的总成本,而不是在交付后修复它。如果在软件交付后出现重大错误,则会增加其有形成本(例如,支出方面)和无形成本(例如,客户不满、公司负面声誉等)。
测试什么?
始终建议对要测试的内容有适当的了解。在本节中,我们首先将了解在测试任何软件时测试人员的主要动机。在测试时,应避免代码覆盖率,即我们的测试套件命中多少行代码。这是因为,在测试时,仅关注代码行数不会为我们的系统增加任何实际价值。即使在部署后,也可能存在一些错误,这些错误会在稍后阶段反映出来。
考虑以下与要测试的内容相关的要点:
我们需要专注于测试代码的功能,而不是代码覆盖率。
我们需要首先测试代码中最重要的部分,然后转向代码中不太重要的部分。这肯定会节省时间。
测试人员必须拥有多种不同的测试,可以将软件推到其极限。
测试并发软件程序的方法
由于能够利用多核架构的真正能力,并发软件系统正在取代顺序系统。近年来,并发系统程序已用于从手机到洗衣机、从汽车到飞机等各种事物中。我们需要更加小心地测试并发软件程序,因为如果我们在已经存在错误的单线程应用程序中添加了多个线程,那么我们最终将得到多个错误。
并发软件程序的测试技术主要集中在选择能够暴露潜在有害模式(如竞争条件、死锁和原子性违规)的交错。以下是两种测试并发软件程序的方法:
系统探索
这种方法旨在尽可能广泛地探索交错的空间。此类方法可以采用蛮力技术,其他方法采用部分顺序减少技术或启发式技术来探索交错的空间。
属性驱动
属性驱动方法依赖于以下观察结果:并发故障更有可能在暴露特定属性(例如可疑内存访问模式)的交错下发生。不同的属性驱动方法针对不同的故障,如竞争条件、死锁和原子性违规,这进一步取决于一个或另一个特定属性。
测试策略
测试策略也称为测试方法。该策略定义了如何进行测试。测试方法有两种技术:
主动
一种在构建创建之前尽早启动测试设计过程以查找和修复缺陷的方法。
被动
一种在开发过程完成后才开始测试的方法。
在对 Python 程序应用任何测试策略或方法之前,我们必须对软件程序可能存在的错误类型有一个基本的了解。错误如下:
语法错误
在程序开发过程中,可能会出现许多小错误。这些错误大多是由于打字错误造成的。例如,缺少冒号或关键字拼写错误等。此类错误是由于程序语法错误而不是逻辑错误造成的。因此,这些错误称为语法错误。
语义错误
语义错误也称为逻辑错误。如果软件程序中存在逻辑或语义错误,则该语句将正确编译和运行,但不会给出所需的输出,因为逻辑不正确。
单元测试
这是测试 Python 程序最常用的测试策略之一。此策略用于测试代码的单元或组件。通过单元或组件,我们的意思是代码的类或函数。单元测试通过测试“小”单元来简化大型编程系统的测试。借助上述概念,单元测试可以定义为一种方法,其中测试单个源代码单元以确定它们是否返回所需的输出。
在我们后续的部分中,我们将学习关于单元测试的不同 Python 模块。
unittest 模块
第一个用于单元测试的模块是 unittest 模块。它受到 JUnit 的启发,并且默认包含在 Python3.6 中。它支持测试自动化、共享测试的设置和拆卸代码、将测试聚合到集合中以及测试与报告框架的独立性。
以下是 unittest 模块支持的一些重要概念
测试夹具
它用于设置测试,以便在开始测试之前运行它,并在测试完成后拆除。它可能涉及在开始测试之前创建临时数据库、目录等。
测试用例
测试用例检查从特定输入集中是否获得了所需的响应。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 会话及其输出。
如果我们的代码一切正常,那么 doctest 模块将不会有任何输出;否则,它将提供输出。
示例
以下 Python 示例使用 docktest 模块来测试名为 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.
现在,我们将更改帮助定义斐波那契模块的代码
以下代码块为例:
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.
在上面的输出中我们可以看到,有三个测试失败了。