随着计算机技术的发展,使得网络应用的数量不断增加,因此网络数据抓包成为了网络应用开发和测试中非常重要的一部分。目前,已有许多网络数据抓包工具可供使用,例如 Wireshark、Tcpdump、Fiddler 等,但这些工具需要手动配置过滤器和网卡信息,而且不能直接将抓到的数据与软件自动化测试结合起来进行分析。因此,本文旨在提出一种利用 Python Pytest Hook 机制的软件自动化测试网络数据抓包方法,在保证网络数据抓包准确性与效率的同时,实现了网络数据抓包与软件自动化测试的结合。
Pytest:是一个用于Python的全功能测试框架,它使编写和执行单元测试、集成测试和功能测试变得更加容易。 Pytest可以充分利用Python的强大功能,提供了很多有用的功能和特性,支持自动发现、模块化测试、参数化、插件扩展、并发执行、测试结果报告等。
Hook:在软件工程中,Hook也称为钩子,是一种基于事件驱动的技术,它可以实现在程序运行某个关键时刻自动执行特定的代码。Hook通常用于在应用程序的生命周期中注册或处理事件,并在特定事件发生时触发相应的回调函数。在Pytest中,Hook也称为钩子函数,是Pytest的一种扩展机制,用于定制和扩展Pytest的功能。Pytest提供了很多默认的Hook函数,可以被Python类或函数实现,以扩展和修改Pytest的默认行为。通过实现Hook函数,我们可以在Pytest的测试流程中进行各种自定义操作,例如:修改测试配置、选择执行的测试用例、在测试用例执行前后执行特定的代码、自定义测试报告等等。本文就是利用了Pytest Hook机制在测试用例执行前后执行特定的代码来实现抓包相关功能的。
我们提出了一种利用 Python Pytest Hook 机制的软件自动化测试网络数据抓包方法。致力于解决使用Pytest时无法按需要同步对测试过程的一个或多个网络数据进行抓包的缺点。
本文针对使用Python Pytest Hook机制实现软件自动化测试网络数据抓包方法给出一种有效的解决方案示例,不需要手动配置网卡信息也不依赖第三方软件,而是通过实现Pytest插件的方式注册到Pytest的执行流程中,通过Hook机制影响Pytest运行自动化测试的流程从而实现在测试执行过程中同步对网络数据进行抓取。
Pytest Hook 抓包执行流程图
网络数据抓包过程随着测试进程的开始而开始,随着测试进程的退出而结束,抓包的数据会在电脑本地以.pcap格式进行存储,并且pcap文件个数和名称均与测试用例保持一致。
- 导入必要的Python库:pytest、scapy、netifaces,其中scapy 是一个功能强大的 Python 库,用于创建、发送和解析网络数据包。它提供了一种简单而灵活的方式来操作网络层、传输层和应用层协议,使我们能够自定义和控制网络通信。netifaces 是一个 Python 库,用于获取和操作网络接口信息。它提供了一种简单的方式来查询和检索系统上的网络接口信息,包括 IP 地址、网络掩码、网关、MAC 地址等。
- 定义MyPlugin 类,该类是 Pytest 插件的主体,MyPlugin 类作为Pytest的插件可以通过注册、加载和Hook函数实现功能的扩展和定制化,与Pytest的API进行交互,如下图所示:
MyPlugin 类图
2.1首先创建MyPlugin类中的属性
- lock:一个线程锁,用于在多线程环境中保证数据的安全访问。
- envConfig: 存储环境配置的文件路径。
- test_pkts: 一个列表,存储捕获到的包。
- test_recordDataPath: 存储 pcap 文件的路径。
- test_caseName: 测试用例的名称。
- test_sniffStopFlag: 指示是否停止包的捕获的标志。
- test_sniffList: 存储要捕获的网卡名称的列表。
- test_thread_List: 存储线程对象的列表。
- recordFlag: 记录 pcap 文件序号的变量。
- tmpFlag: 记录临时 pcap 文件序号的变量。
2.2 进一步创建MyPlugin类中的方法
- _write_cap(): 定义一个方法,用于将捕获到的包添加到 test_pkts 列表中,并根据 pcapThreshold(抓包文件拆分阈值) 的值进行 pcap 临时文件的保存,pcapThreshold是记录在config.txt文件中的一个配置项,使用者可以根据自己电脑配置情况进行设置,默认40000,抓包过程中会在文件到达60MB左右时进行拆包,最后进行聚合,数值越小,拆包会越频繁,如果电脑剩余内存不够,可以适当调小该值。总的来说这个方法的作用就是在保证使用者电脑内存资源安全的前提下不断的做网络抓包数据存储的操作。
config.txt配置文件的格式为:
[sniffManager]
pcapfilter = "not port 22 and not port 80 and not port 8080"
pcapthreshold = 40000
- _stopfilter(): 定义一个方法,判断是否需要停止包的捕获。由于抓包动作是随着测试开始而开始的,并且是在一个不会影响测试主流程的多线程环境下执行的,因此除了做到与测试同步结束之外,还应该提供一个由使用者控制的停止方法,_stopfilter就是为此而设计的,它可以被使用者在测试过程中的任意位置调用,从而实现整体的抓包操作停止。默认情况下我们采用的是跟随自动化测试流程的启动和停止方法。
- _sniffmsg(): 定义一个方法,自动获取网卡信息并保存配置到一个名为envConfig.py的配置文件中,用于捕获指定网卡上的包,并调用 _write_cap 方法将包保存到 pcap 文件。该方法是抓包功能的核心,它将调用_write_cap、_stopfilter以及一个抓包过滤配置,该方法启动后将会以阻塞的形式不间断的对指定的网卡进行网络数据抓包操作。
envConfig.py配置文件格式为:
ETH = {
'name': '以太网',
'record': 'Y',
'ip': 'xxx.xxx.xxx.xxx',
'netmask': '255.255.255.0',
'gateway': "('xxx.xxx.xxx.xxx',)",
'dns': "('xxx.xxx.xxx.xxx', 'xxx.xxx.xxx.xxx')"
}
- _start_logger(): 定义一个方法,创建一个线程池用来调用_sniffmsg执行抓包操作,因为_sniffmsg会阻塞当前程序,所以使用多线程来解决这个问题,使其不会影响Pytest测试主程序的执行,这里使用多线程还有一个考虑,那就是通常较为复杂的测试场景中,使用者的电脑可能不止一块网卡,所以该方法实现了根据网卡个数来分配线程资源,从而实现多网卡的抓包操作。
- _save_pcap(): 定义一个方法,用于保存 pcap 文件。这里会分阶段对保存的pcap文件进行管理,主要实现了两大功能一是管理并命名拆分的抓包过程文件,二是最终以测试用例的名称对抓包文件进行聚合和重命名,目的是保证整个抓包过程中使用者电脑的资源消耗是最低的且一旦出现意外退出时能够做到最大化的抓包数据留存,使用者不再需要在测试过程中还要对抓包数据进行备份、重命名、分开存储这些操作。
- pytest_sessionstart(): pytest 框架的Hook函数,用于在测试会话开始之前进行初始化操作,这里主要用于启动网络抓包动作_start_logger。
- pytest_runtest_teardown(): pytest 框架的Hook函数,用于在每个测试用例结束之后调用保存 pcap 文件的逻辑。
- pytest_sessionfinish(): pytest 框架的Hook函数,用于在测试会话结束之后进行资源清理操作,如用于存放网络数据的test_pkts以及线程资源等。
- 对不想抓包的端口在配置文件config.txt中进行过滤设置,配置格式如下:
pcapfilter = "not port 22 and not port 80 and not port 8080"
4.启动 pytest 框架,运行测试用例,并注册MyPlugin插件:pytest.main(args=argList,plugins=[MyPlugin(recordDataPath)]),这里我们将MyPlugin类通过pytest.main的启动函数中的plugins传入,在此之前还需要对recordDataPath参数进行设置,该参数用于指定最终网络抓包数据文件的存放路径。
5.自动化测试用例结束后得到结合自动化测试用例执行的网络数据pcap文件。