2.3 自动化测试平台的基本设计
经过以上两节的分析,读者对需要实现什么样的自动化测试平台有了基本的了解,接下来本节就对将要实现的自动化测试平台做一个基本的设计。
2.3.1 自动化测试平台的基本模块
在2.2.2节中我们分析了自动化测试流程的基本形式,下面介绍自动化测试平台的基本模块。
首先是测试资源,一般用户将测试资源的信息通过数据储存在文件或数据库中。所以,测试资源管理可以作为一个基本模块。
然后是对测试的配置,包括执行的配置及测试用例的配置——测试配置管理也是一个基本模块。
接着是测试的执行,测试平台执行输入的测试用例,并且输出测试结果,在这一过程中,测试用例执行是一个基本模块,测试结果(测试报告和日志)的输出也可以作为一个基本的模块。这样,我们就可以大概地勾勒出整个测试系统的模块框图及其调用关系,如图2-10所示。
图2-10 测试系统基本调用关系框图
接下来的几节,将会对每个模块需要实现的功能及其调用者进行分析、设计,每个模块会用单独的一节来介绍其实现方法,供读者参考。
2.3.2 测试资源管理模块
在软件测试过程中,测试资源是最基本的要素,不管是测试工具、被测对象,还是辅助工具,不管是硬件还是软件,我们都可以使用测试资源这一概念来描述。描述的目的是记录这些现实环境中的资源的属性和静态配置,比如资源类型、型号、管理地址等,测试用例需要从资源配置信息中获取所需信息,进行配置及测试结果的比较。
对于测试资源模块,我们设计如下功能:
(1)测试资源描述方法的定义
我们用什么样的数据结构描述测试资源呢?通过字典,还是键-值对,还是将对象描述成类?在测试资源模块中,资源描述的数据结构是特定的。此外,作为通用的模块,资源的描述不能带入具体业务的固定描述,只能让模块的使用者自己扩展或定义。至于是普通属性,还是具体业务属性,其分界线并不好定义,可能对整个团队来说是一个普通属性,但是对跨团队来说就是一个具体的业务属性。对一个测试WIFI产品的团队而言,WIFI端口就是一个普通的属性,但是对其他团队而言,WIFI端口就是一个具体业务的属性。因此,我们要考虑的测试资源的描述方法必须是可以被大多数团队所接受的。
(2)测试资源的保存和读取
一般来说,自动化测试的环境是相对比较稳定的,所以整个测试环境的描述完成后,就需要把这些描述数据储存下来,存放到文本文件或数据库中,下一次测试时读取已经保存的文件。
(3)测试资源的选择
测试工程师在开发测试用例的时候,需要通过测试资源的配置信息来获取所需的测试资源。出于对测试用例的复用性的考虑,我们不能指定其测试资源,以免当一个测试用例被换掉时测试环境无法执行,所以资源配置模块就需要提供功能,让测试用例开发工程师可以根据需要,选择所希望获得的测试资源来进行使用。
2.3.3 测试配置管理模块
任何软件的运行都离不开配置,对于测试平台也是如此。一个软件系统的配置具有多个层面,可以是系统级别的配置,也可以是功能级别的配置。很多开发人员有这样的经验——当一个功能的某个变量需要通过配置来提供时,就会将这个变量放在配置文件中,并存放到一个特定目录下。如果没有一个统一的流程去规划这个过程,那么每个测试工程师都会按照自己喜欢的模式去定义配置文件格式,比如XML、Properties、JSON等,并且都存放在自己认为合适的地方,导致配置文件混乱,不方便使用且难以管理。所以配置模块的目的就是让其他模块通过配置模块来统一管理配置项。
对于配置模块,我们实现如下功能:
(1)配置的保存和读取
配置文件的保存和读取是配置模块的基本功能之一,所有配置都被保存在文件或数据库中,以供读取,所以该模块需要实现配置数据的序列化和反序列化功能。同时,不同消费者的定义字段和数据完全不同,所以该模块也需要有对不同配置进行序列化和反序列化的能力。
(2)配置自动生成和默认值
对软件的使用者来说,在不了解软件系统的情况下创建配置文件是不太可能的,所以如果一个系统或模块在使用前没有任何配置,那么在运行的过程中也需要对默认值进行初始化,并生成相应的初始化配置文件。
(3)动态配置能力
并不是所有的配置都需要放在一个地方集中管理,有时需要在测试执行的过程中生成配置文件,比如针对单个测试用例的配置。这时,测试配置模块需要给其他模块提供接口,以生成、储存和读取相应的配置项。
(4)带逻辑功能的配置
有些选项配置在完成之后,需要执行一些特定的逻辑,这些逻辑的功能本身可能比较简单,不足以单独封装成一个模块。这时就需要有一个功能让开发者实现这一逻辑,我们称之为带逻辑功能的配置。比如,在实现一个配置的过程中,一旦测试用例执行错误数超过5个,就发送通知邮件。如果单独做这个功能,可以在测试执行层面上简单地实现。如果作为一个可扩展的配置,就需要通过带逻辑功能的配置来实现,而非通过将代码插入测试执行的模块来实现。
2.3.4 测试用例执行模块
当资源配置和测试配置完成后,就需要选择测试用例并开始执行。所以测试执行模块是自动化测试的核心模块,如果把自动化测试比作一辆车,那么测试执行模块就是这辆车的引擎,所以笔者也给这个模块取了一个名字——测试引擎。测试引擎主要负责所有的配置输入,包括测试资源、测试配置,以及所要执行的测试用例,执行后通过测试报告和日志模块进行输出。Python的UnitTest和PyTest本身可以作为测试引擎模块来使用,也可以基于这两个开源包进行二次开发,但是本书还是通过自己的方法来实现测试引擎模块,以加深读者对测试执行功能的理解。
测试执行模块需要有以下功能:
(1)测试资源、配置和测试报告的初始化
测试执行模块需要根据用户指定的测试资源和配置信息,将其初始化并生成相应的实例,以提供给测试用例。
(2)测试用例配置注入
测试用例本身是一个脚本文件,它在执行的过程中需要测试引擎来提供测试资源、配置信息,以及测试用例本身的信息。测试用例本身可以引用资源管理模块和配置管理模块,从功能的边界来说,资源管理模块和配置模块的初始化,以及之后的逻辑操作应该由测试执行模块负责,将初始化后的实例传递给测试用例。所以相应地,针对测试引擎,需要设计测试用例的基本形态,这也是测试用例开发者需要遵循的一个模式。
(3)测试用例列表的执行逻辑
一个自动化测试执行过程一般来说不会只有一个测试用例,测试执行模块接收的测试用例可以是单个测试用例,也可以是多个测试用例的集合,我们称之为测试列表。对测试列表来说,测试执行模块需要对测试的执行逻辑进行控制,比如测试用例的执行顺序、执行条件等。而对一个测试用例来说,测试执行模块要对其生命周期进行管理,负责测试用例的初始化、执行和最后的清理,并且能够对测试用例中未经处理的异常进行捕获,使其不影响其他测试用例的执行。
2.3.5 测试报告和日志模块
最终,测试用例执行的结果需要输出成一个可视化的格式,提供给测试工程师进行分析。相应地,测试过程中一些外部模块的日志和测试资源的日志,也需要提供给测试工程师,以方便问题的排查,这些事情就需要通过测试报告和日志模块来实现。
测试报告和日志模块主要有以下几方面的功能:
(1)测试步骤格式化输出
在测试执行的过程中,可以将测试步骤通过一定的格式输出,并以一定的数据结构保存在文件或数据中。最简单的格式输出,可以是文本的输出结果,但是输出大量的文本不利于结果分析,所以我们需要设计一定的数据结构去描述输出的结果,并且结合前端的渲染工具进行结果的查找。比如,将每个步骤设计成一个条目,以条目为单位进行查找。
(2)测试执行过程的日志
只有测试步骤结果的输出是不够的,在测试执行过程中,测试资源本身会产生日志,或者对测试资源的操作也需要通过日志来记录,这些操作也会成为测试工程师分析测试结果的有力信息。所以也需要通过日志模块进行收集。
(3)日志注册机制
Python提供了标准的logging库,可以方便地记录log日志。如果希望能够统一管理这些日志,就不能直接使用logging库,而是让测试报告和日志模块通过注册机制来统一管理平台上其他模块所产生的日志。
(4)日志分类
对于自动化测试平台来说,平台本身的模块会产生日志,测试用例执行过程中会产生日志,测试资源也会产生日志。所以测试报告和日志模块需要对日志进行分类,储存在不同的路径下,并且在测试用例的执行过程中,也需要将不同测试用例产生的日志进行适当的分类。