对于接口自动化框架,CI持续集成是一个无法绕开的话题。讨论这个话题,说实话还是有一点不知从何说起..或许应该拆开为多个话题去讨论,因为要讨论的点确实太多,既然这样,那么我就以我在实际工作中见到的一些接口自动化框架实现方案在CI上存在的一些设计不足来做讨论吧,可能这样更能戳到痛点。
我们先结合接口自动化框架的实际落地情况来说吧。通常公司的测试开发人员开发了一套接口自动化框架,然后可能会有多个系统(应用)的接口测试代码需要通过这套框架去做统一的测试代码研发,通常每个系统(应用)的测试代码在测试环境调试通过后,都会合并到master分支,然后将master分支的最新代码在测试环境或者生产环境运行来满足全量接口功能测试环境巡检和部分接口功能(基本是核心业务功能)生产环境巡检的测试需求。
而把git仓库中master分支的最新代码发布到服务器的工作通常都由Jenkins来完成。有些公司或许开发了自己的devops平台,而devops平台的本质也是把Jenkins的功能通过容器化部署的方式集成了进去,那对我们的影响就是,如果有devops平台,就无需要考虑自己去搭建jenkins,如果没有devops平台,则需要测试团队自己去搭建发布测试项目的jenkins,或者直接联系运维人员去搭建,毕竟无论是测试软件项目还是业务软件项目对运维人员来说没有任何区别,然而关于Jenkins的搭建,我们这里不做讨论。
上述描述了ci的工作本质,我们也提到结合实际的自动化框架实现方案在CI上的设计不足,那么我先描述一个理想的实现效果吧。无论是否结合devops平台,我们需要做到的理想CI效果是,一个master分支集成多个系统(应用)的测试代码,无论是生产还是测试环境,可以自由的选择测试范围,并且测试结果可以按照系统(应用)通知给对应的研发、测试、产品。从运行的层面上说就是,一次运行,多份测试报告,每份测试报告的测试结果发送给对应(系统)的相关人员。
结合我实际工作中见到的一些接口自动化框架存在的一些问题如下:
1、一个系统(应用)一个master分支,也就是独立的一个仓库。多个系统就会存在多个仓库多个master分支,在jenkins的体现上就是多个job,在devops平台的体现就是多个任务
2、多个系统一个master分支,代码是同一份,然而在Jenkins的体现却是a系统的测试代码会复制master分支的代码另起一个分支如master_a创建一个job,b系统(应用)的代码复制master分支代码另起一个分支如master_b创建一个job,devops的体现也是多个任务,本质上还是多个分支,只是在同一个仓库
其实无论上述哪一种CI实现方案,其实对代码维护上带来了很大的影响,而且容易误操作,都是存在设计缺陷的。
还是和之前一样,先展示实现上述红字部分的实现效果。
首先,展示我要运行的两个系统(应用)的测试代码:
先运行一个系统(应用),example1,运行如下:
本地生成1份测试报告
发送1份测试报告:
运行2个系统(应用)的测试代码,example1,example2,运行如下:
生成两份测试报告:
发送两份邮件:
实现思路及实现源码展示:
思路:
1、接入系统的配置以系统为维度,定义一个应用名称
2、运行的run方法加上for循环,通过应用名称去找应用并运行
import pyfiglet
from termcolor import colored
from common.push_ding_message import DingRobot
from common.runCaseManage import AllTest
from common.args_processing import parse_args
from config_file.application_info import application_info
from common.report_directory_processing import DelReport
from common.write_cmd_values_2_file import SetEnv
class Run:
def __init__(self):
self.art_str()
self.run()
@staticmethod
def art_str():
ascii_art = pyfiglet.figlet_format('hawk-api', font='slant')
colored_ascii_art = colored(ascii_art, color='cyan')
print(colored_ascii_art)
@staticmethod
def run():
delr = DelReport()
delr.del_reportfiles()
se = SetEnv()
args = parse_args()
env = args.get('env')
attr = ','.join(args.get('mark')) if args.get('mark') else 'all mode has no attr_value'
mode = args.get('mode')
applicationlist = args.get('app')[0].split(',')
# print(applicationlist)
se.envchange(env, attr)
for application in applicationlist:
try:
obj = AllTest(application, application_info[application]["report_service"]["email"], env, attr.split(','), is_filter=mode)
obj.run(application_info[application]["test_info"]['alias'])
if application_info[application]['report_service']["ding"] != {}:
dr = DingRobot(application_info[application]['report_service']["ding"])
dr.push_ding_msg()
else:
obj.logger.info('dingtalk配置缺失,请检查dingtalk配置...')
except Exception as e:
print(e)
本章我分了多个章节,此章节只是展示实现效果,下个章节会讲解具体设计,以及unittest可以实现而pytest无法实现的原因