基于TestNG+Rest Assured+Allure的接口自动化测试框架

基于TestNG+Rest Assured+Allure的接口自动化测试框架一 前言当今 自动化测试 大行其道 其中 接口自动化测试 便是同行们谈得最多的话题之一

大家好,欢迎来到IT知识分享网。

基于TestNG+Rest Assured+Allure的接口自动化测试框架

一、前言

当今,“自动化测试”大行其道,其中“接口自动化测试”便是同行们谈得最多的话题之一。了解测试金字塔分层理念的童鞋都清楚,接口自动化测试有以下优点。

  • 投入低,产出高。
  • 比UI自动化更稳定。
  • 比单元测试更接近真实业务。

正因为以上优点,接口自动化测试逐渐成为了业界主流,各种工具/框架层出不穷,比如Postman,Jmeter,Htttpclient,Rest assured,HttpRunnerManager等。

二、背景
此前笔者曾基于Jenkins+Ant+Git+Jmeter搭建过一套接口自动化框架,期间亦针对Jmeter做了许多功能的扩展,比如:生成excle结果文件、数据库断言、自动提交缺陷、自动更新案例执行结果至Testlink等。虽说Jmeter简单易上手,但在笔者看来,其并不是接口自动化测试的首选,其中的原因暂不祥谈,毕竟仁者见仁。
近段时间,笔者一直在思索,学习前辈们优秀的经验,并从公司项目架构出发,搭建了一套基于Jenkins+Maven+Git+TestNG+RestAssured+Allure的持续集成测试框架,相比原先Jmeter的那套,其易用性更好、效率更高、扩展性更强。

三、框架理念

基于TestNG+Rest Assured+Allure的接口自动化测试框架

  • 接口自动化测试框架
  • 根据用例模板编写测试用例(包含响应报文断言及接口入参等)。
  • 编写数据库断言文件。
  • 编写测试类。
  • 配置环境及测试用例集。
  • Jenkins选择运行环境及用例集,触发构建。
  • 生成测试报告,邮件通知相关人员。

四、操作步骤

1、编写用例

基于TestNG+Rest Assured+Allure的接口自动化测试框架

用例文件名称与测试类名一致,比如开户的测试类名为OpenAcc,则用例文件名为OpenAcc.xls,用例模板由以下几部分组成。

  • caseNo、testPoint分别与案例管理系统的案例编号、案例标题对应,方便后续同步执行结果。
  • preResult为响应报文断言,目前支持jsonpath、包含断言、不包含断言。
  • YorN为案例执行标志,Y表示执行。
  • tableCheck为数据库断言标志,Y表示进行数据库断言。
  • 其他字段为接口入参,目前支持以下五种供数方式。

(1)自定义函数供数。引用格式为:__phone()表示生成11位手机号。__idno()表示生成18位身份证号。

(2)查询数据池供数。引用格式为:${dp.sql(select accountNo from M_account where status = 1)}

(3)查询数据库供数。引用格式为:${db.sql(select accountNo from M_account_card where status = 1)}

(4)先接口请求,然后提取响应报文供数。引用格式为:KaTeX parse error: Expected ‘}’, got ‘EOF’ at end of input: …g.case023.post(.data.code)},表示先以post方式发送SendmsgYg接口请求,然后再提取响应报文的code字段。支持接口之间的多重依赖。

(5)先接口请求,然后查询数据库/池供数。引用格式为:${SendmsgYg.case023.post.db.sql(select accountNo from M_account_card where status = 1)},表示先以post方式发送SendmsgYg接口请求,然后再查询数据库(db)/数据池(dp)获取数据。

2、编写数据库断言

<?xml version="1.0" encoding="utf-8"?> <dbCheck dbCheck_name="开户绑卡数据库检查点"> <caseNo case_no="case085"> <!--案例编号--> <table table_name="M_ACCOUNT"> <!--表名--> <priKey key_name="ACCOUNT_NO">ACCOUNT_NO</priKey> <!--主键--> <column column_name="CUST_ID">CUST_ID</column> <!--其他字段的预期结果--> <column column_name="MERCHANT_ID">MERCHANT_ID</column> <!--其他字段的预期结果--> <column column_name="ACCOUNT_STATUS">1</column> <!--其他字段的预期结果--> <column column_name="ORGAN_NO">0019901</column> <!--其他字段的预期结果--> </table> </caseNo> <caseNo case_no="case086"> <table table_name="M_ACCOUNT_CARD"> <priKey key_name="ACCOUNT_NO">ACCOUNT_NO</priKey> <priKey key_name="CARD_NO">CARD_NO</priKey> <column column_name="CARD_TYPE">2</column> <column column_name="MERCHANT_ID">MERCHANT_ID</column> <column column_name="CUST_ID">CUST_ID</column> <column column_name="CARD_IMG">CARD_IMG</column> <column column_name="OPEN_BANKNAME">NOTNULL</column> </table> </caseNo> </dbCheck> 

对于未确定的预期结果,使用变量代替,后续编写测试类时再做映射。

3、编写测试类

测试类分为两大类,一是只需响应报文断言,二是需要响应报文及数据库断言。测试人员按照以下模板编写脚本即可。

/* *短信发送接口 * 环境参数在SetUpTearDown 父类定义 */ @Feature("分类账户改造") public class SendmsgYg extends SetUpTearDown { 
    @Story("发送短信") @Test(dataProvider = "dataprovider", dataProviderClass = DataProviders.class, description = "发送短信") public void runCase(String caseMess, String bodyString) throws IOException, SQLException, ClassNotFoundException { 
    //发送请求 Response response = RunCaseJson.runCase(bodyString, "post"); //只进行响应报文断言 asserts(caseMess, bodyString, response.asString(),"",null); } } 

数据库断言文件中的变量,可通过调用封装的方法取值,比如查数据库、提取响应报文、调用接口等方式。

/* *开立分类账户 * 环境参数在SetUpTearDown 父类定义 */ @Feature("分类账户改造") public class OpenYg extends SetUpTearDown { 
    @Story("分类账户开户") @Test(dataProvider = "dataprovider", dataProviderClass = DataProviders.class, description = "开户") public void runCase(String caseMess, String bodyString) throws IOException, SQLException, ClassNotFoundException { 
    //发送请求 Response response = RunCaseJson.runCase(bodyString, "post"); //如果需要数据库断言,此处添加断言文件变量的map映射 //可通过调用封装的方法取值,比如查数据库、提取响应报文、调用接口等方式。 Map<String, String> map = new HashMap<>(); //查询数据库获取,取不到值返回"" String account = DataBaseCRUD.selectData("select accountNo from M_ACCOUNT where status =1"); //提取响应报文,取不到值返回"" String custId = RespondAssertForJson.getBuildValue(response.asString(),"$.data.custid"); //执行SendmsgYg接口的case023案例,然后提取响应报文的merchanId ,取不到值返回"" String merchanId = RespondAssertForJson.getBuildValue("","${SendmsgYg.case023.post($.data.merchanId)}"); map.put("ACCOUNT_NO",account); map.put("CUST_ID",custId); map.put("MERCHANT_ID",merchanId); //断言(包含响应报文断言和数据库断言) String xmlFileName = this.getClass().getSimpleName(); //数据库断言xml文件名(与类名保持一致) asserts(caseMess, bodyString, response.asString(),xmlFileName,map); } } 

4、用例集

对于多个suite,可通过suite-files配置。testng.xml文件配置如下。

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="IIACCOUNT自动化测试" parallel="classes"> <listeners> <!--失败重跑--> <listener class-name="com.iiaccount.listener.FailedRetryListener"/> </listeners> <test verbose="2" name="IIACCOUNT_YG"> <classes> <class name="com.iiaccout.yiguan.OpenYg"/> <class name="com.iiaccout.yiguan.SendmsgYg"/> </classes> </test> </suite> 

5、Jenkins构建

选择环境及测试用例集,开始构建,构建完成后生成测试报告及日志。也可根据需要设置定时构建,持续进行质量监控。
Jenkins构建

Jenkins构建后

Jenkins构建

6、报告分析

在这个注重颜值的世界,allure框架出来的测试报告绝对称得上“报告界的小鲜肉”。

测试报告总览包含用例通过率、测试套件、环境、feature、类别、趋势等信息。以下示例截图的案例全部执行失败,所以总览的通过率是0%。
测试报告

类别主要展现失败的用例信息,可根据项目情况自定制报告内容,比如请求报文、响应报文、断言结果等。
测试报告

测试报告

时间刻度展现了每条案例的执行时间。
测试报告

五、框架实现方案

1、工具/框架

  • Jenkins
  • Maven
  • Gitlab
  • TestNG
  • Rest Assured
  • Allure

2、工程目录

基于TestNG+Rest Assured+Allure的接口自动化测试框架

基于TestNG+Rest Assured+Allure的接口自动化测试框架

工程目录

工程目录

3、pom依赖

支持多环境(sit,uat)切换,结合Jenkins使用。

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>HFIIACCOUNT</groupId> <artifactId>ApiAutoTest</artifactId> <version>1.0-SNAPSHOT</version> <!--通过“-D”引用变量--> <properties> <aspectj.version>1.8.10</aspectj.version> <!-- 解决mvn编译乱码问题--> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!--外部传参--> <xmlFileName></xmlFileName> </properties> <dependencies> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.11</version> </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>ru.yandex.qatools.allure</groupId> <artifactId>allure-testng-adaptor</artifactId> <version>1.3.6</version> <exclusions> <exclusion> <groupId>org.testng</groupId> <artifactId>testng</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.qameta.allure</groupId> <artifactId>allure-testng</artifactId> <version>2.0-BETA14</version> </dependency> <dependency> <groupId>net.sourceforge.jexcelapi</groupId> <artifactId>jxl</artifactId> <version>2.6.12</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.13</version> </dependency> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc14</artifactId> <version>10.2.0.4.0</version> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> <filters> <filter>src/main/filters/filter_${ 
   env}.properties</filter> </filters> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.20</version> <configuration> <argLine> -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" </argLine> <!--生成allure-result的目录--> <systemProperties> <property> <name>allure.results.directory</name> <value>./target/allure-results</value> </property> </systemProperties> </configuration> <dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${ 
   aspectj.version}</version> </dependency> </dependencies> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19</version> <configuration> <suiteXmlFiles> <!--该文件位于工程根目录时,直接填写名字,其它位置要加上路径--> <!--suiteXmlFile>src/main/resources/testngXml/${ 
   xmlFileName}</suiteXmlFile--> <suiteXmlFile>${ 
   project.basedir}/target/classes/testngXml/${ 
   xmlFileName}</suiteXmlFile> </suiteXmlFiles> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>8</source> <target>8</target> </configuration> </plugin> <!--增加此配置,防止编译后xls文件乱码--> <!--Maven resources 插件会对文本资源文件进行转码,但是它无法区分文件是否是纯文本文件还是二进制文件.于是二进制文件在部署过程中也就被转码了.--> <!--https://blog.csdn.net/xdxieshaa/article/details/--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.6</version> <configuration> <nonFilteredFileExtensions> <!-- 不对xls进行转码 --> <nonFilteredFileExtension>xls</nonFilteredFileExtension> </nonFilteredFileExtensions> </configuration> </plugin> </plugins> </build> <!--通过“-P”引用变量--> <profiles> <!-- uat测试环境 --> <profile> <id>uat</id> <properties> <env>uat</env> </properties> </profile> <!-- sit测试环境 --> <profile> <id>sit</id> <properties> <env>sit</env> </properties> <activation> <activeByDefault>true</activeByDefault><!--默认启用的是sit环境配置--> </activation> </profile> </profiles> </project> 

4、实现思路

  • 将每个接口的案例读取到Map保存,其中key值为每条案例的caseNo+testPoint+preResult+YorN+tableCheck拼装(也是一个map),value值为剩余字段(接口入参)的拼装,即接口请求的bodyString。

案例模板

public static void getMap(Sheet sheet, int cols, int row, String pubArgs){ 
    for (int col = 0; col < cols; col++) { 
    String cellKey = sheet.getCell(col, 0).getContents();//表头 String cellValue = sheet.getCell(col, row).getContents();//值 if (col >= 5) { 
    //appid,api,version属于公共入参,公共入参字段在PublicArgs.properties文件进行配置 // getBuildValue(value1,value2)方法用于转换${}或者函数为对应的值 if (pubArgs.toLowerCase().contains(cellKey.toLowerCase().trim())) { 
    bodyMap.put(cellKey, RespondAssertForJson.getBuildValue("", sheet.getCell(col, row).getContents())); } else { 
    dataMap.put(cellKey, RespondAssertForJson.getBuildValue("", sheet.getCell(col, row).getContents())); } } else { 
    caseMessMap.put(cellKey, cellValue); } } bodyMap.put("data", dataMap); map.put(new Gson().toJson(caseMessMap), new Gson().toJson(bodyMap)); } 
  • 对于案例中的自定义函数或供数变量,封装了方法RespondAssertForJson.getBuildValue(var1,var2)进行转换,目前暂支持前文提到的五种供数方式,后续可根据需要进行扩展。
 / * 支持json串转换 * 支持自定义函数的转换 * 支持${}变量转换 * * @param sourchJson * @param key * @return */ public static String getBuildValue(String sourchJson, String key) { 
    key = key.trim(); Matcher funMatch = funPattern.matcher(key); Matcher replacePattern = replaceParamPattern.matcher(key); log.info("key is:" + key); try{ 
    if (key.startsWith("$.")) { 
   // jsonpath key = JSONPath.read(sourchJson, key).toString(); //jsonpath读取对应的值 log.info("key start with $.,value is:" + key); } else if (funMatch.find()) { 
   //函数 String args = funMatch.group(2); //函数入参 log.info("key is a function,args is:" + args); String[] argArr = args.split(","); for (int index = 0; index < argArr.length; index++) { 
    String arg = argArr[index]; if (arg.startsWith("$.")) { 
    //函数入参亦支持json格式 argArr[index] = JSONPath.read(sourchJson, arg).toString(); } } log.info("argArr:"+argArr.length); String value = FunctionUtil.getValue(funMatch.group(1), argArr); //函数名不区分大小写,返回函数值 log.info("函数名 funMatch.group(1):" + funMatch.group(1)); key = StringUtil.replaceFirst(key, funMatch.group(), value); //把函数替换为生成的值 log.info("函数 funMatch.group():" + funMatch.group()); log.info("key is a function,value is:" + key); } else if (replacePattern.find()) { 
   //${}变量 log.info("${}变量体:"+replacePattern.group(1)); String var = replacePattern.group(1).trim(); String value1 = DataBuilders.dataprovide(var); key = StringUtil.replaceFirst(key, replacePattern.group(), value1); //把变量替换为生成的值 log.info("key is a ${} pattern,value is:" + key); } return key; }catch(Exception e){ 
    log.info(e.getMessage()); return null; } } 
  • 通过TestNG的@DataProvider获取Map的案例信息,进行接口请求。约定测试案例名称为:测试类名.xls
 /* *map包含两部分json,key为caseNo等信息,value为接口入参 */ @DataProvider(name = "dataprovider") public static Object[][] dataP(Method method) throws IOException, BiffException, URISyntaxException { 
    String className = method.getDeclaringClass().getSimpleName(); //获取类名 String caseFileName = className+".xls"; //测试案例名称为:类名.xls Object[][] objects = null; Map<String,String> map = new HashMap<String, String>(); map = AssembledMessForJson.assembleMess(caseFileName,""); //""表示读取所有的为Y的case objects = new Object[map.size()][2]; int i=0; for(Map.Entry<String, String> entry : map.entrySet()){ 
    objects[i][0] = entry.getKey(); objects[i][1] = entry.getValue(); i++; } map.clear(); //需清空map,否则案例会不断叠加 2018-10-19 add by lrb return objects; } 
  • 所有的测试类都继承SetUpTearDown父类(详见前文例子),父类中使用@BeforeSuite,@BeforeClass,@AfterSuite等注解来进行参数准备或数据清理。

父类部分方法:

//环境配置 @BeforeClass public void envSetUp() { 
    try { 
    String system = "env.properties"; //环境由filter配置 RestAssured.baseURI = new GetFileMess().getValue("baseURI", system); RestAssured.basePath = new GetFileMess().getValue("basePath", system); RestAssured.port = Integer.parseInt(new GetFileMess().getValue("port", system)); } catch (IOException e) { 
    e.printStackTrace(); } } 
  • 对每条案例进行断言,目前暂支持响应报文断言和数据库断言,后续可根据需要扩展。
    响应报文断言:将案例文件的preResult字段(预期结果)与接口响应报文进行比对,预期结果暂支持jsonpath,包含,不包含断言,引用格式为:KaTeX parse error: Expected group after ‘_’ at position 13: .status=200;_̲_contain(lrr);_….cdoe=1000,多个断言使用英文分号隔开。
    数据库断言:将测试类名.xml断言文件中的预期结果与数据库实际结果进行比对,各个字段的比对结果在测试报告中展现。
  • 对于抛异常的案例,失败重试。
/* *实现IAnnotationTransformer接口,修改@Test的retryAnalyzer属性 */ public class FailedRetryListener implements IAnnotationTransformer { 
    public void transform(ITestAnnotation iTestAnnotation, Class aClass, Constructor constructor, Method method) { 
    { 
    IRetryAnalyzer retry = iTestAnnotation.getRetryAnalyzer(); if (retry == null) { 
    iTestAnnotation.setRetryAnalyzer(FailedRetry.class); } } } } 
  • 测试报告展现请求报文,响应报文,断言结果等信息。
/* *测试报告展现 */ public class TestStep { 
    public static void requestAndRespondBody(String URL, String Body,String Respond){ 
    requestBody(URL,Body); respondBody(Respond); } @Attachment("请求报文") public static String requestBody(String URL, String body) { 
    //格式化json串 boolean prettyFormat = true; //格式化输出 JSONObject jsonObject = JSONObject.parseObject(body); String str = JSONObject.toJSONString(jsonObject,prettyFormat); //报告展现请求报文 return URL+"\n"+str; } @Attachment("响应报文") public static String respondBody(String respond) { 
    //报告展现响应报文 return respond; } @Attachment("数据库断言结果") public static StringBuffer databaseAssertResult(StringBuffer assertResult){ 
    //报告展现数据库断言结果 return assertResult; } @Attachment("响应报文断言结果") public static StringBuffer assertRespond(StringBuffer assertResult){ 
    //报告展现数据库断言结果 return assertResult; } } 
  • 日志采集,log4j.properties配置如下。
log4j.rootLogger=INFO, stdout, D , E log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%-d{ 
   yyyy-MM-dd HH:mm:ss} [ %C.%M(%L) ] - [ %p ] %m%n # 文件达到指定大小的时候产生一个新的文件 log4j.appender.D=org.apache.log4j.DailyRollingFileAppender # TODO 部署时,修改为指定路径 log4j.appender.D.File=logs/apiAutoTest_debug.log log4j.appender.D.Append = true # 输出DEBUG级别以上的日志 log4j.appender.D.Threshold = DEBUG log4j.appender.D.layout=org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern=%-d{ 
   yyyy-MM-dd HH:mm:ss} [ %C.%M(%L) ] - [ %p ] %m%n 保存异常信息到单独文件 log4j.appender.E = org.apache.log4j.DailyRollingFileAppender 异常日志文件名 # TODO 部署时,修改为指定路径 log4j.appender.E.File = logs/apiAutoTest_error.log log4j.appender.E.Append = true 只输出ERROR级别以上的日志!!! log4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern = %-d{ 
   yyyy-MM-dd HH:mm:ss} [ %C.%M(%L) ] - [ %p ] %m%n 

5、Jenkins配置

5.1、插件安装

可在线安装插件或下载到本地安装,下载地址。

  • Maven Integration
  • Allure
  • TestNG Results
  • Parameterized Trigger
  • Email Extension

5.2、Jenkins配置

新建一个maven项目。

新建项目

全局工具配置(Jenkins-系统管理-全局工具配置)。

全局工具配置

全局工具配置

参数化构建过程配置,选择【choice Parameter】,配置的Name需与pom.xml文件的变量名一致,字典根据源码中实际用途定义。此处需注意,profiles定义的属性通过“-P”引用,下文会提及。
参数配置

参数配置

源码管理配置,此处根据源码管理工具配置。

源码管理配置

build配置,此处通过clean test -P e n v − D x m l F i l e N a m e = {env} -DxmlFileName= envDxmlFileName={xmlFileName}来把参数传给pom,-P和-D的区别可百度。

build配置

配置构建后操作,即测试报告生成路径。

构建后操作

6、构建测试

Jenkins构建

六、关注点

  • 整套框架使用的是ojdbc,Maven配置ojdbc依赖需做特殊处理,详情戳此链接。
  • 编译后,测试案例.xls文件乱码。原因是Maven resources
    插件会对文本资源文件进行转码,但是它无法区分文件是纯文本文件还是二进制文件,二进制文件在部署过程中也就被转码了。需要在pom文件增加如下配置。
 <!--增加此配置,防止编译后xls文件乱码--> <!--Maven resources 插件会对文本资源文件进行转码,但是它无法区分文件是否是纯文本文件还是二进制文件.于是二进制文件在部署过程中也就被转码了.--> <!--https://blog.csdn.net/xdxieshaa/article/details/--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.6</version> <configuration> <nonFilteredFileExtensions> <!-- 不对xls进行转码 --> <nonFilteredFileExtension>xls</nonFilteredFileExtension> </nonFilteredFileExtensions> </configuration> </plugin> 

mvn编译后出现乱码。需要在pom文件增加如下配置。

<properties> <aspectj.version>1.8.10</aspectj.version> <!-- 解决mvn编译乱码问题--> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> 
  • log4j.properties配置的日志路径为项目路径下,不便于长期管理,部署时应在另指定存储路径。
  • Jenkins控制台输出乱码,解决方法如下。

(1)、设置jenkins所在服务器环境变量,添加系统变量。
变量名:JAVA_TOOL_OPTIONS
变量值:-Dfile.encoding=UTF8
(2)、修改Tomcat配置,进入apache_tomcat/conf文件夹下,编辑server.xml,在Connector port=”8080″后面加入useBodyEncodingForURI=“true”

(3)、启动tomcat,运行jenkins,进入系统管理→系统设置,在全局属性处勾选Environment variables,添加编码环境变量LANG=zh_CN.UTF-8

  • 脚本统一放到Git管理,暂定代码分支管理规则如下。

master作为稳定的分支,测试人员在dev分支进行脚本编写,执行无误再合并master分支,然后触发Jenkins自动构建。
新建dev分支

新建dev分支并Checkout

后续在dev分支进行脚本编写,脚本调试无误后再push到远程的dev分支,然后合并到master分支。
git Commit

git push

切换到master分支,然后合并dev分支内容,然后再push到远程仓库。
分支合并

更详细的操作可参考idea中git分支的使用。

  • 如果jenkins的服务器部署在内网,而自己公司又没有专门的maven远程仓库,第一次构建可能无法链接外网下载依赖包导致报错,可通过以下方式解决。
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> <!-- localRepository | The path to the local repository maven will use to store artifacts. | | Default: ${ 
   user.home}/.m2/repository <localRepository>/path/to/local/repo</localRepository> --> <localRepository>C:/Users/wtapp01/.m2/repository</localRepository> 

七、框架扩展

上述框架目前仅局限于测试端,严格意义上来说并不算真正的持续集成,后续再完善以下几点。

  • 增加缺陷确认,提交缺陷,然后同步案例管理系统。
  • 与单元测试打通。
  • 增加代码覆盖率检查。
  • 搭建统一供数平台,通过restful api访问。

八、github

https://github.com/Tomandy08/ApiAutoTest

文末分享:这下面有我学习整理出来的自动化测试资料,以及大厂面试(附带答案)待你来领取~ 见公众号:【伤心的辣条】愿你我都有所获…

基于TestNG+Rest Assured+Allure的接口自动化测试框架
基于TestNG+Rest Assured+Allure的接口自动化测试框架

合理利用自己每一分每一秒的时间来学习提升自己,不要再用”没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

我的测试学习交流群: 群里有技术大牛一起交流分享~

原文不易呀,眼睛都留眼泪了!麻烦伸出发财小手点个赞,感谢您的支持,你的点赞是我持续更新的动力。

推荐好文:

包装成1年工作经验的测试工程师,我给他的面试前的建议如下

自动化测试到底要学什么?

为何跳槽不考虑腾讯?聊聊我和鹅厂的一点往事

自动化测试和手动测试哪个更高级?

新手必看:怎么写一个合格的测试用例?

python登录接口测试问题记录与解决 ( 干 货 )

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/155841.html

(0)
上一篇 2025-02-16 18:33
下一篇 2025-02-16 18:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信