热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Pythonassert实现软件测试

Python对于测试非常看重,例如测试中最常见的操作——断言assert,其在Python中就是一个关键字而不是一个函数。而在C语言中,assert只是一个普通的函数。从这点也可以

Python 对于测试非常看重,例如测试中最常见的操作——断言 assert,其在 Python 中就是一个关键字而不是一个函数。而在 C 语言中,assert 只是一个普通的函数。从这点也可以看出,Python 将测试当作最基础的部分。

可以通过使用下面的代码来查看 Python 语言定义的关键字:

>>> import keyword # 引入模块keyword
>>> keyword.kwlist # 得到所有的关键字
# 关键字列表
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await',
'break', 'class', 'continue', 'def', 'del', 'elif', 'else',
'except', 'finally', 'for', 'from', 'global', 'if', 'import',
'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass',
'raise', 'return', 'try', 'while', 'with', 'yield']

可以直接是使用 assert 在源代码中对其进行测试,常用的做法如图 1 所示。




图 1 将测试代码和实现功能放入同一个文件

下面看一个简单的例子,假定自定义了一个模块 sampleAssert,其代码如下:

def int_list_sort(input_list): # 被测对象,完成对输入的整数列表排序
input_list.sort() # 完成排序
if __name__ == "__main__": # 判断条件,里面的内容是用来测试的
def test_normal_positive_input(): # 定义一个测试用例
input_list = [3, 5, 9, 1, 8]
int_list_sort(input_list)
assert input_list == [1, 3, 5, 8, 9]
print("test_normal_positive_input: PASS")
test_normal_positive_input() # 执行测试用例

如果我们是 import(引入)该模块,case 是不会执行的,即第 3 行开始的块是不会执行的,所以包含在该块内的测试用例定义不会被看到,测试用例也不会被执行。

$ python # 启动解释器,Python 3
Python 3.7.3 (default, Mar 27 2019, 16:54:48)
[Clang 4.0.1 (tags/RELEASE_401/final)] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sampleAssert # 引入我们刚才定义的模块
>>> sampleAssert.test_normal_positive_input() # 测试函数是不可见的
Traceback (most recent call last):
File "", line 1, in
AttributeError: module 'sampleAssert' has no attribute 'test_normal_
positive_input'
>>> list_obj = [3, 1, 6, 100, 98, 9]
>>> sampleAssert.int_list_sort(list_obj) # 被测对象是可见的
>>> list_obj
[1, 3, 6, 9, 98, 100] # 排序后的结果

如果是直接运行该脚本,则测试用例就会被触发。

$ python sampleAssert.py
test_normal_positive_input: PASS

下面我们来实现一个冒泡排序法,其仅对整数列表有效。冒泡排序法是最简单的排序法,其通过交换相邻的元素来实现排序。下面以对包含 4 个元素 3、1、5、2 的列表进行排序为例来解释这个过程,如图 2 所示。




图 2 冒泡排序

首先从尾部,也就是下部依次查找不符合排列要求的相邻两个数,第一次找到的是 5 和 2,交换它们,然后继续查找得到 3 和 1 这两个不符合要求的相邻数,交换它们。通过这一轮的交换,最小的数交换到了第一个元素。然后继续其他记录的排序,第二轮可以保证第二小的数排到第二个位置上。以此类推,最多经过 n-1 轮就可以完成所有数据的排序。

在这个例子中,经过了两轮就完成了所有数据的排序。

下面是完整的实现代码和相关测试代码:

def bubble_sort(input_list): # 被测函数,冒泡排序
if type(input_list) is not type([]): # 如果输入参数不符合要求
print("Invalid Input Type")
return None
for x in input_list: # 有元素不是整数,返回None
if type(x) != int:
return None
input_len = len(input_list)
print()
print("Origin:", input_list)
if input_len <= 1: # 没有元素或者仅包含一个元素
return input_list
for x in range(input_len-1): # 如果顺序不对,和旁边的元素交换
swap_happens = False
for y in range(input_len-1, x, -1):
if input_list[y-1] > input_list[y]:
input_list[y-1], input_list[y] = input_list[y], input_
list[y-1]
swap_happens = True
if swap_happens == False: # 上一轮没有交换数据,已经排序完毕
break
print("Temp %d:" % x, input_list)
return input_list # 返回排序完毕的列表
if __name__ == "__main__": # 如果是运行该脚本而不是引入该脚本
import random # 测试代码开始
def test_empty_input(): # 如果输入的列表为空
input = []
output = bubble_sort(input)
assert type(output) == type([])
assert len(output) == 0
def test_invalid_input(): # 如果输入的不是列表
output = bubble_sort(1)
assert output is None
def test_one_element(): # 如果列表仅包含一个元素
input = [1, ]
output = bubble_sort(input)
assert type(output) == type([])
assert len(output) == 1
assert output[0] == 1
def test_neg_one_element(): # 如果列表仅包含一个元素,而且不是整数
input = ["name", ]
output = bubble_sort(input)
assert output is None
def test_two_element(): # 如果列表仅包含两个元素
input = [18, 8]
output = bubble_sort(input)
assert type(output) == type([])
assert len(output) == 2
assert output[0] == 8
assert output[1] == 18
def test_neg_two_element(): # 如果列表包含两个元素,但并不都是整数
input = [1, "name"]
output = bubble_sort(input)
assert output is None
def test_normal_pos(): # 正常输入
input = [88, 1, 20, 8, 9, 21, 98, 76]
output = bubble_sort(input)
expected_output = [1, 8, 9, 20, 21, 76, 88, 98]
assert output == expected_output
def test_dup_elements(): # 如果有重复的元素
input = [88, 1, 20, 8, 9, 21, 98, 8, 76] # 两个8
print("input:", input)
output = bubble_sort(input)
print("outpout:", output)
expected_output = [1, 8, 8, 9, 20, 21, 76, 88, 98]
assert output == expected_output
def test_all_same(): # 如果所有元素都相等
input = [8, 8, 8, 8, 8, 8] # 所有的输入元素相同
output = bubble_sort(input)
expected_output = [8, 8, 8, 8, 8, 8]
assert output == expected_output
def random_test(): # 随机生成测试数据
# 生成随机的输入数据
expected_list_len = random.randint(10, 100)
input_list = []
for x in range(expected_list_len):
input_list.append(random.randint(-100, 100))
input_len = len(input_list)
org_input = input_list.copy() # 备份一下元素数据
output = bubble_sort(input_list)
print("org_input", org_input)
#input_len = len(org_input)
assert len(output) == expected_list_len
for pos in range(input_len-1):
val = output[pos]
# 该数据在原始列表中存在
# 这样可以确保所有结果列表中的数据都是来自输入列表
assert val in org_input
# 而且其出现的次数和元素列表中出现的次数一致
# 这可保证输入列表中的数据不会丢失
assert output.count(val) == org_input.count(val)
# 保证有序,从小到大
assert val <= output[pos+1]
def test_random_data(): # 随机输入测试
# 进行100轮随机输入的测试
for x in range(100):
random_test()
# 执行所有的测试
test_empty_input()
test_invalid_input()
test_one_element()
test_neg_one_element()
test_two_element()
test_neg_two_element()
test_normal_pos()
test_dup_elements()
test_all_same()
test_random_data()

可以发现测试代码的长度比被测代码的长度还要长,这是软件测试中,尤其是功能测试部分常见的现象。另外一个现象是对于针对特殊使用场景的测试用例数量比较大。多数情况下,问题不会隐藏在常用的使用场景,而多隐藏在这些不常见的使用场景中,所以针对这些特殊使用场景的测试用例的设计需要多下功夫。


推荐阅读
  • Android目录遍历工具 | AppCrawler自动化测试进阶(第二部分):个性化配置详解
    终于迎来了“足不出户也能为社会贡献力量”的时刻,但有追求的测试工程师绝不会让自己的生活变得乏味。与其在家消磨时光,不如利用这段时间深入研究和提升自己的技术能力,特别是对AppCrawler自动化测试工具的个性化配置进行详细探索。这不仅能够提高测试效率,还能为项目带来更多的价值。 ... [详细]
  • 本题库精选了Java核心知识点的练习题,旨在帮助学习者巩固和检验对Java理论基础的掌握。其中,选择题部分涵盖了访问控制权限等关键概念,例如,Java语言中仅允许子类或同一包内的类访问的访问权限为protected。此外,题库还包括其他重要知识点,如异常处理、多线程、集合框架等,全面覆盖Java编程的核心内容。 ... [详细]
  • 计算 n 叉树中各节点子树的叶节点数量分析 ... [详细]
  • 本文首先对信息漏洞的基础知识进行了概述,重点介绍了几种常见的信息泄露途径。具体包括目录遍历、PHPINFO信息泄露以及备份文件的不当下载。其中,备份文件下载涉及网站源代码、`.bak`文件、Vim缓存文件和`DS_Store`文件等。目录遍历漏洞的详细分析为后续深入研究奠定了基础。 ... [详细]
  • 如何使用Python高效绘制矩形图形
    本文详细介绍了如何利用Python的Turtle库高效绘制矩形图形,适合初学者快速上手。通过具体示例代码,帮助读者理解Turtle库的基本绘图方法和技巧,同时探讨了在不同应用场景中绘制矩形的实际操作,为后续复杂图形的绘制打下坚实基础。 ... [详细]
  • 本文详细介绍了如何在Linux系统中搭建51单片机的开发与编程环境,重点讲解了使用Makefile进行项目管理的方法。首先,文章指导读者安装SDCC(Small Device C Compiler),这是一个专为小型设备设计的C语言编译器,适合用于51单片机的开发。随后,通过具体的实例演示了如何配置Makefile文件,以实现代码的自动化编译与链接过程,从而提高开发效率。此外,还提供了常见问题的解决方案及优化建议,帮助开发者快速上手并解决实际开发中可能遇到的技术难题。 ... [详细]
  • Go语言实现Redis客户端与服务器的交互机制深入解析
    在前文对Godis v1.0版本的基础功能进行了详细介绍后,本文将重点探讨如何实现客户端与服务器之间的交互机制。通过具体代码实现,使客户端与服务器能够顺利通信,赋予项目实际运行的能力。本文将详细解析Go语言在实现这一过程中的关键技术和实现细节,帮助读者深入了解Redis客户端与服务器的交互原理。 ... [详细]
  • 在该项目中,参与者需结合历史使用模式和天气数据,以预测华盛顿特区自行车共享系统的租赁需求。数据分析部分首先涉及数据的收集,包括用户骑行记录和气象信息,为后续模型构建提供基础。通过深入的数据预处理和特征工程,确保数据质量和模型准确性,最终实现对自行车租赁需求的有效预测。 ... [详细]
  • 开发心得:利用 Redis 构建分布式系统的轻量级协调机制
    开发心得:利用 Redis 构建分布式系统的轻量级协调机制 ... [详细]
  • 在 Windows 10 系统下配置 Python 3 和 OpenCV 3 的环境时,建议使用 Anaconda 分发版以简化安装过程。Anaconda 可以从其官方网站(https://www.anaconda.com/download)下载。此外,本文还推荐了几本关于 Python 和 OpenCV 的专业书籍,帮助读者深入理解和应用相关技术。 ... [详细]
  • 进程(Process)是指计算机中程序对特定数据集的一次运行活动,是系统资源分配与调度的核心单元,构成了操作系统架构的基础。在早期以进程为中心的计算机体系结构中,进程被视为程序的执行实例,其状态和控制信息通过任务描述符(task_struct)进行管理和维护。本文将深入探讨进程的概念及其关键数据结构task_struct,解析其在操作系统中的作用和实现机制。 ... [详细]
  • 在处理大规模并发请求时,传统的多线程或多进程模型往往无法有效解决性能瓶颈问题。尽管它们在处理小规模任务时能提升效率,但在高并发场景下,系统资源的过度消耗和上下文切换的开销会显著降低整体性能。相比之下,Python 的 `asyncio` 模块通过协程提供了一种轻量级且高效的并发解决方案。本文将深入解析 `asyncio` 模块的原理及其在实际应用中的优化技巧,帮助开发者更好地利用协程技术提升程序性能。 ... [详细]
  • 深入解析 C 语言与 C++ 之间的差异及关联
    深入解析 C 语言与 C++ 之间的差异及关联 ... [详细]
  • 利用 Python 实现 Facebook 账号登录功能 ... [详细]
  • 本文详细介绍了在Ubuntu操作系统中使用GDB调试工具深入分析和调试标准库函数`printf`的源代码过程。通过具体步骤和实例,展示了如何设置断点、查看变量值及跟踪函数调用栈,帮助开发者更好地理解`printf`函数的工作原理及其内部实现细节。 ... [详细]
author-avatar
咸咸
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有