高效自动化测试平台:设计与开发实战
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.3 从资源类对象获取资源配置接口

测试资源的提供本质上是为了提供测试环境的配置信息,其中包括测试资源的配置接口的连接信息,比如串行口的波特率、SSH接口的IP地址、用户名和密码等,测试代码根据这些信息对测试资源进行连接。所以在测试资源配置实现之后,需要考虑如何通过这些资源配置来获取相应的配置接口。

3.3.1 资源类对象和配置接口分离

从面向对象的角度来说,当我们用类描述资源的时候,很容易会想到将一些对象的操作方法也封装到其中,然后直接在测试用例中调用。虽然看上去是合理的,但是从模块化的设计思想出发,我们仅仅希望一个模块负责单一的功能,而不是将很多逻辑操作都一股脑地封装在一起。

当一个团队设计了资源类的属性之后,如果将所有的逻辑操作都封装在ResourceDevice中,那么资源包就会需要很多外部依赖。比如一个设备,支持Telnet管理,就需要引用Telnet包,如果支持SSH管理,则需要引用SSH包,如果支持Web管理,就需要引用Selenium包。过多的依赖不仅让平台的管理变得麻烦,也会使部署变得不灵活,甚至显得太重。试想,如果另一个团队也想复用这个资源包,但是他们并不使用Web,没有安装Selenium,那么为了使用这个包,就需要安装Selenium——虽然意义不大,仅仅是为了解决一个组件的依赖。

配置接口是用来管理测试资源的接口,是代码用来向测试资源发送和接收信息的重要途径。对于一些简单的接口,比如基于文本协议的命令行Telnet、SSH、串行口等,可以使用相应的库进行封装,在调用的时候进行实例化。此外,还有很多复杂的管理接口,诸如需要测试资源设备供应商提供的连接控件、图形接口(GUI)等,需要实现更复杂的库。

但是无论这些接口的实现如何复杂,其实例化过程中所需要的参数都可以通过资源模块来提供,所以我们可以通过设计一个标准的配置接口来获取方法,将资源模块本身和真正实现接口的模块完全解耦合,如图3-10所示。

图3-10 测试资源端口管理实例和资源的解耦

如图3-10所示,这样的模块关系使得测试资源模块可以单独使用,而资源接口的模块也能被单独使用,中间通过耦合逻辑来实现参数的输入。如图3-10中虚线部分所示,当添加新的设备3类型时,资源管理模块不用做任何修改,只需添加设备3的配置模块,并通过配置实例化接口获取相应的配置信息,以及实例化相应的配置接口实例。

3.3.2 配置接口实例化方法的注册

要将配置接口的实例化和资源配置模块分开,基本思想是资源管理模块不负责具体的实例化,而让调用者根据获取的资源设备类型自己来实例化。比如我们有一个SSH服务器的设备资源类型,配置了其登录属性、IP地址、端口、用户名和密码等信息,那么实例化这个服务器或其配置接口的方法可以通过如下代码来实现:

如上代码所示,SshServer类用来描述SSH服务器的配置端口,为了创建其实例必须提供其登录信息,我们通过collect_device方法获取相应的配置信息,再通过其构造方法进行实例化。

这是一个可行的方法,但是由于这些代码很可能在测试用例中,测试工程师需要了解所有配置接口的创建方法。我们能否创建一个文件,把所有所需设备的配置接口的实例化方法都存放在该文件内,并把资源对象作为参数呢?这也不失为一个方法,但是测试用例开发者仍然需要知道用哪个方法来实例化配置接口。

有没有一种方法,可以通过资源对象直接返回配置接口呢?

3.3.2.1 回调机制

在编程语言特性中,所谓回调就是将函数或方法作为参数,传递给另一个函数或方法,在不同的编程语言中有不同的实现。比如,C中的指向函数的指针、Java中的事件,或者C#中的代理函数,都是实现回调的方法。假设函数或方法A的参数是一个函数或方法,A在执行的过程中,能执行该参数传递的函数或方法,所以提供不同的函数或方法给A,执行的结果就会不同。

在Python中,由于函数或方法本身是对象,所以可以通过参数直接传递给其他函数,具体实现代码如下:

上述代码中,testA的参数是一个方法,在testA的执行过程中调用了这个方法,并传递了一个参数“hello”。method1和method2是两个不同的方法,各自对参数进行了不同的处理,将这两个方法分别传递给testA去执行,执行结果为:

因此,我们把testA作为测试资源对象中的一个获取资源配置接口实例的方法,method1和method2分别是不同资源配置接口实例化的方法,而参数hello就是测试资源对象本身的信息,这样我们就可以通过这种回调机制来处理配置接口的实例化。

3.3.2.2 统一注册机制

我们希望实例化的方法是不传递任何参数的,这样测试用例开发者就不需要关心到底用什么方法来实例化配置接口。所以我们在回调机制上做一些改进,把需要调用的方法提前注册,并生成资源类型和实例化方法之间的映射关系。

我们在资源模块中添加两个字典,来保存资源类型和实例化方法的映射关系,然后在资源类中添加用于实例化配置接口的方法,具体实现代码(core/resource/pool.py)如下:

然后,在相应的ResourceDevice和DevicePort类中,添加方法用于实例化:

测试开发者只需将配置接口实例化的方法实现后,放在统一的地方一起注册,测试用例开发者就可以使用get_comm_instance方法直接获取配置接口实例,具体实现代码(product/resource/instancecreation.py)如下:

create_ssh和create_telnet这两个方法是用来实例化SSH和Telnet配置接口的,通过register_resource方法进行注册。该文件处于某个测试项目的业务代码中,而非核心的资源管理模块,所以测试用例开发工程师可以根据测试项目中用到的测试设备,自行添加各种资源类型到配置接口实例化方法的映射关系中。这样,测试用例开发工程师就能方便地获取相应的配置接口实例,具体实现代码如下: