
2.2 函数库
看似模块化已经解决了代码复用率低的问题,为什么还要使用函数库呢?先来看看以下两个问题。
1)公司有多个Web项目,每个Web项目均可使用公共函数层的封装,如何在不同项目之间共享呢?
2)IMS项目为库存管理系统,假设销售系统需要和IMS交互,比如这样一个场景:销售系统销售一个物品后,需要查看IMS中的该物品是否为出库状态。这个场景不可避免地要登录IMS,并做相关物品库存状态的校验操作。也就是说,业务函数层的封装也应该是可跨项目共享的。那么应该如何共享呢?
对于以上两个问题,读者可能会认为直接复制就行了,这的确是一种解决方式,但并不是最好的。假设一个测试项目需要依赖多个公共函数层和业务函数层的封装,并且公共函数层和业务函数层的代码还在不停地变更,这样通过复制的方式就很难保证项目的完整性和时效性。
更好的方式是将可跨项目共享的代码单独打包供不同测试项目引入和使用,这些被单独打包的代码称为函数库。
2.2.1 使用Maven私有仓库
当测试项目依赖某个函数库时,这个函数库就称为该测试项目的依赖包。公司内部大多架设Maven私有仓库来跨项目共享依赖包。
Maven私有仓库只是一个角色,Nexus、Artifactory和Archiva等都可以充当该角色。Nexus是Maven私有仓库中使用最广泛的一个,本节笔者也使用Nexus来介绍函数库的共享。
Nexus分OSS版和Professional版,OSS为免费版本,因此笔者使用的是Nexus OSS(以下简称Nexus)版本。Nexus的搭建方法请自行查阅相关资料,这里重点介绍需要设置的地方。
考虑到下载速度,最好将公共仓库设置为国内的。这里将maven-central中的“Remote storage”设置为阿里云Maven仓库,地址为http://maven.aliyun.com/nexus/content/groups/public/。如图2-1所示,这样所有Maven的工程可通过Nexus连接到阿里云Maven仓库,从阿里云Maven仓库下载的依赖包会存储在Nexus中,以后其他Maven项目也需要该依赖包时直接从Nexus下载即可。

图2-1 配置Nexus的Maven仓库地址
2.2.2 发布函数库
编写函数库的测试人员需要将函数库发布到Maven私有仓库,以便供其他测试人员使用。
1.配置Maven
配置Maven需要配置本地的settings.xml文件及Maven工程的pom.xml文件。本地的settings.xml文件内容如下。



对以上配置的解释如下。
<mirrors>标签中配置仓库地址,<mirrorOf>标签中使用星号(*)代表拦截所有仓库类型,即将所有依赖的正式版本和快照版本均指向了Nexus的地址。
<profiles>支持配置多个<profile>,以便切换不同的配置。<repositories>和<pluginRepositories>标签分别用于配置依赖包和依赖插件的仓库地址。<repository>和<pluginRepository>标签中的ID必须匹配<servers>标签中的Server ID。<enabled>标签用于控制是否可从该仓库下载正式版和快照版的依赖包。<properties>标签中配置了Maven编译使用的JDK版本。
<activeProfiles>标签用于设置需要激活的配置。<activeProfile>标签中的ID必须与<profile>中的ID匹配。
<servers>标签中用于配置仓库的用户名和密码,其中的Server ID必须与<mirrors>标签中的Mirror ID匹配。
Maven工程的pom.xml文件新增以下内容。


<distributionManagement>标签用于配置仓库地址。具体来说<repository>标签用于配置正式版本的仓库地址,而<snapshotRepository>标签则用于配置快照版本的仓库地址。它们中的ID必须与settings.xml文件<servers>标签中的Server ID匹配。
以上配置文件中的yourip、yourport、yourprofileid、yourusername和yourpassword需根据实际情况进行替换。
2.调整项目结构
在chapter-02模块中再新建3个Maven模块,即common、business和testcase,如图2-2所示。

图2-2 chapter-02模块结构
将AbstractTestClass、LoginLogic和Login类分别移动到common、business和testcase模块中。根据规范,测试代码(本节中的Login类)放在/src/test/java目录,非测试代码(本节中的AbstractTestClass和LoginLogic类)放在/src/main/java目录。
3.发布函数库到Maven私有仓库
依次执行以下命令将common和business函数库发布到Nexus。


以上命令中的“-am”表示打包依赖的父级模块,因此打包后会多出automated-testing-advanced和chapter-02,加上本身的common和business一共4个函数库被打包并发布到了Nexus,如图2-3所示。

图2-3 发布到Nexus的函数库
新建工程或模块时,默认的版本号后缀为“-SNAPSHOT”,因此会发布到Nexus的maven-snapshots仓库,如需发布到maven-releases仓库,去掉该后缀即可。
注意:如果修改了函数库的代码,但是不修改版本号,默认情况下是无法重复发布到maven-releases仓库的,不过可以在Nexus中将发布策略设置为“Allow redeploy”取消该限制,但一般不建议这么做,因为不同的代码使用同样的版本号并不是一种规范的版本管理方式。
2.2.3 使用函数库
由于测试用例需要依赖公共函数库和业务函数库,因此testcase模块是函数库的使用方。
首先在testcase模块的pom.xml文件中加入以下依赖,加入后Maven会自动引入这些依赖包到模块中。


请注意,以上的GAV(groupId、artifactId和version)值为笔者设置的,读者需根据实际情况进行替换。
然后在Login类中导入AbstractTestClass类,因为调整项目结构之前Login类与AbstractTestClass类处于同一个包中,因此不需要显式导入,而此时必须显式导入。另外,需要重新导入登录方法,因为它所在的包已经改变了。
修改后的Login类如下所示。

注意:出于便捷考虑,示例中将公共函数库和业务函数库放在了同一个工程里,在实际项目中应该把公共函数库单独放在一个工程中。这样做之后,不管是逻辑上还是物理上都达到了解耦的目的。
至此,本节在模块化的基础上实现了函数库的共享,这对测试用例分层具有更实际的意义。