本文共 15132 字,大约阅读时间需要 50 分钟。
接着来完善我们的Rest Assured框架,我在github上搜索到了一些国内和国外的基于Rest Assured写的java语言的接口自动化框架。基本上就是分两种。第一种就是采用excel文件来写接口用例,然后TestUtils中写一个poi读取excel文件的方法。这种思想是数据驱动,框架本身和用例代码很少,核心就是一个一个读取excel中的接口测试用例。第二个类型,就是我们这里介绍的风格。看他们封装的TestBase和TestUtils和我们这一样。
所以,这种思想是一致的。具体用例管理和某一些方面的优化,看具体项目,不一定人人都适合。我也是推荐大家学一些思想,比较上层的一些框架设计组件和套路,真正能解决问题还是用例怎么写,怎么覆盖,怎么管理的,这些经验只有在真实的接口自动化项目中才能学习和得到锻炼。
1.优化前面代码
前面一篇文章的代码,我们只考虑到了接口请求方法是get,并没有考虑post, put,delete等。所以,我先定义了一个类变量 request,在TestBase中并没有写死reuqest后面跟着就是get("xxxurl"),这样我们在具体的测试用例代码中就可以,req.get或者req.post()来调用。由于get和post请求还不一致,post请求一般参数都使用body传递,一般都是采用hashmap集合。所以前面的TestBase中getResponsetByPath()不好进行封装,这里我就删除了相关不用的方法。
package com.anthony.base;import java.util.ResourceBundle;import org.apache.log4j.Level;import org.apache.log4j.Logger;import org.apache.log4j.PropertyConfigurator;import org.testng.annotations.AfterClass;import org.testng.annotations.BeforeClass;import com.anthony.utils.TestUtils;import io.restassured.RestAssured;import io.restassured.http.ContentType;import io.restassured.path.json.JsonPath;import io.restassured.response.Response;import io.restassured.specification.RequestSpecification;public class TestBase { public static RequestSpecification httpRequest; public static Response response; public Logger logger; public static String serverHost; public static String port; //Global Setup Variables public Response res = null; //Response public JsonPath jp = null; //JsonPath //测试用例中断言代码能用上这里的 testUtils对象 public static TestUtils testUtils = new TestUtils(); //初始化请求对象 public RequestSpecification req; static { // 用于加载properties文件 // 注意这里不需要文件扩展名.properties ResourceBundle rb = ResourceBundle.getBundle("config"); serverHost = rb.getString("Host"); port = rb.getString("Port"); } @BeforeClass public void setup() { String className = this.getClass().getName(); logger = Logger.getLogger(className); PropertyConfigurator.configure("log4j.properties"); logger.setLevel(Level.DEBUG); setBaseURI(); //设置Base URI //设置Base Path,我这里是api(https://reqres.in/接口地址都是api开头, //所以这里basepath设置api这个字符串),看看具体你自己项目请求地址结构 setBasePath("api"); req = RestAssured.given().contentType(ContentType.JSON); } @AfterClass public void afterTest (){ //测试之后恢复一些值的设定 resetBaseURI(); resetBasePath(); } //设置 base URI public static void setBaseURI (){ if("80".equals(port)) { RestAssured.baseURI = serverHost; }else { RestAssured.baseURI = serverHost+":"+port; } //System.out.println(RestAssured.baseURI); } //设置base path public static void setBasePath(String basePath){ RestAssured.basePath = basePath; } //执行完测试后重置 Base URI public static void resetBaseURI (){ RestAssured.baseURI = null; } //执行完测试后重置 base path public static void resetBasePath(){ RestAssured.basePath = null; } //返回 JsonPath对象 public static JsonPath getJsonPath (Response res) { String json = res.asString(); //System.out.print("returned json: " + json +"\n"); return new JsonPath(json); }}
下面get测试类代码更改如下,测试可以成功通过。
package com.anthony.cases;import org.testng.annotations.Test;import com.anthony.base.TestBase;public class ListUsersTest extends TestBase { // get https://reqres.in/api/users?page=2 @Test public void test01_ListUsers() { res = req.get("/users?page=2"); jp = getJsonPath(res); testUtils.checkStatusCode(res, 200); testUtils.printAllResponseText(res); }}
上面测试用例中,req是从TestBase类中继承得到对象,所以测试用例代码中不需要声明和导入包。由于这里接口是get的请求类型,所以直接reg.get()就得到响应,并赋值给res.
2.增加一个Post接口用例代码
来看一个接口请求类型是post的例子。
这是一个注册接口,参数是json格式,有两个参数name和job. 参数是需要放在请求的body中传递,是一个json类型数据。下面代码我们写了两种post请求,区别就在于参数的组装过程。
package com.anthony.cases;import java.util.HashMap;import org.testng.annotations.Test;import com.anthony.base.TestBase;public class CreateTest extends TestBase { // post https://reqres.in/api/users // parameters: name, job @Test public void test01_Create() { res = req.param("name","anthony@163.com") .param("job", "tester") .header("Content-Type", "text/html") .when().post("/users"); testUtils.checkStatusCode(res, 201); testUtils.printResponseBody(res); } @Test public void test02_Create() { HashMapmap = new HashMap (); map.put("name","anthony12@126.com"); map.put("job","dev"); res = req.formParams(map) .header("Content-Type", "text/html") .when().post("/users"); testUtils.checkStatusCode(res, 201); testUtils.printResponseBody(res); }}
运行是可以通过
[RemoteTestNG] detected TestNG version 6.14.3{ "id": "149", "createdAt": "2019-09-05T11:59:16.896Z"}io.restassured.internal.ValidatableResponseImpl@293bb8a5PASSED: test02_Create
整体来说,get的请求简单,post请求稍微复杂一些,需要对照API文档,进行请求数据的组装。
3.添加extent report集成
下面来介绍添加一个extent report组件,可以通过testNG产生的HTML报告,得到更加美观的HTML报告。
首先更新一下pom.xml,配置maven build,就是输入mvn clean install,可以执行testng.xml管理的测试用例。
4.0.0 com.restassured RestAssured 0.0.1-SNAPSHOT http://maven.apache.org UTF-8 org.apache.maven.plugins maven-compiler-plugin org.apache.maven.plugins maven-surefire-plugin 2.18.1 testng.xml io.rest-assured rest-assured 4.0.0 test io.rest-assured json-path 4.0.0 io.rest-assured json-schema-validator 4.0.0 io.rest-assured xml-path 4.0.0 org.testng testng 6.14.3 test org.hamcrest java-hamcrest 2.0.0.0 test log4j log4j 1.2.17 com.aventstack extentreports 3.1.5 provided com.vimalselvam testng-extentsreport 1.3.1
然后写一个extent report的配置文件
dark UTF-8 https Extent APT Automation Test Report bottom
最后在utils包下写一个报告的类
package com.anthony.utils;import java.io.File;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import org.testng.ITestContext;import org.testng.ITestResult;import org.testng.TestListenerAdapter;import com.aventstack.extentreports.ExtentReports;import com.aventstack.extentreports.ExtentTest;import com.aventstack.extentreports.ResourceCDN;import com.aventstack.extentreports.Status;import com.aventstack.extentreports.markuputils.ExtentColor;import com.aventstack.extentreports.markuputils.MarkupHelper;import com.aventstack.extentreports.reporter.ExtentHtmlReporter;import com.aventstack.extentreports.reporter.configuration.ChartLocation;import com.aventstack.extentreports.reporter.configuration.Theme;public class Reporting extends TestListenerAdapter { public ExtentHtmlReporter htmlReporter; public ExtentReports extent; public ExtentTest logger; public void onStart(ITestContext testContext) { String timeStamp = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss").format(new Date());//time stamp String reportName="Test-Report-"+timeStamp+".html"; htmlReporter=new ExtentHtmlReporter(System.getProperty("user.dir")+ "/test-output/"+reportName);//specify location of the report htmlReporter.loadXMLConfig(System.getProperty("user.dir")+ "/extent-config.xml"); extent=new ExtentReports(); extent.attachReporter(htmlReporter); extent.setSystemInfo("Host name","localhost"); extent.setSystemInfo("Environemnt","QA"); extent.setSystemInfo("user","pavan"); htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS); htmlReporter.config().setDocumentTitle("XXXX Test Project"); // Tile of report htmlReporter.config().setReportName("Functional Test Report"); // name of the report htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP); //location of the chart htmlReporter.config().setTheme(Theme.DARK); } public void onTestSuccess(ITestResult tr) { logger=extent.createTest(tr.getName()); // create new entry in th report logger.log(Status.PASS,MarkupHelper.createLabel(tr.getName(),ExtentColor.GREEN)); // send the passed information to the report with GREEN color highlighted } public void onTestFailure(ITestResult tr) { logger=extent.createTest(tr.getName()); // create new entry in th report logger.log(Status.FAIL,MarkupHelper.createLabel(tr.getName(),ExtentColor.RED)); // send the passed information to the report with GREEN color highlighted String screenshotPath=System.getProperty("user.dir")+"\\Screenshots\\"+tr.getName()+".png"; File f = new File(screenshotPath); if(f.exists()){ try { logger.fail("Screenshot is below:" + logger.addScreenCaptureFromPath(screenshotPath)); } catch (IOException e) { e.printStackTrace(); } } } public void onTestSkipped(ITestResult tr) { logger=extent.createTest(tr.getName()); // create new entry in th report logger.log(Status.SKIP,MarkupHelper.createLabel(tr.getName(),ExtentColor.ORANGE)); } public void onFinish(ITestContext testContext) { extent.flush(); } }
测试运行
只要你机器环境配置了maven的环境变量到path,在cmd中切换到当前Eclipse的工程所在根目录,执行命令 mvn clean install 回车
[INFO][INFO] --- maven-surefire-plugin:2.18.1:test (default-test) @ RestAssured ---[INFO] Surefire report directory: C:\Users\Anthony\eclipse-workspace\RestAssured\target\surefire-reports------------------------------------------------------- T E S T S-------------------------------------------------------Running TestSuite{ "id": "286", "createdAt": "2019-09-06T11:45:23.180Z"}io.restassured.internal.ValidatableResponseImpl@a77614d{ "id": "650", "createdAt": "2019-09-06T11:45:25.673Z"}io.restassured.internal.ValidatableResponseImpl@59a67c3aHTTP/1.1 200 OKDate: Fri, 06 Sep 2019 11:45:26 GMTContent-Type: application/json; charset=utf-8Transfer-Encoding: chunkedConnection: keep-aliveSet-Cookie: __cfduid=d9a3336c50a948adc43d1bcd32af0ed7d1567770326; expires=Sat, 05-Sep-20 11:45:26 GMT; path=/; domain=.reqres.in; HttpOnly; SecureX-Powered-By: ExpressAccess-Control-Allow-Origin: *Etag: W/"414-k36Lu9tCb0XMJeh2/UG19C4xbw4"Via: 1.1 vegurCF-Cache-Status: HITAge: 3701Expires: Fri, 06 Sep 2019 15:45:26 GMTCache-Control: public, max-age=14400Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"Vary: Accept-EncodingServer: cloudflareCF-RAY: 5120325f2ad0d94e-HKGContent-Encoding: gzip{ "page": 2, "per_page": 6, "total": 12, "total_pages": 2, "data": [ { "id": 7, "email": "michael.lawson@reqres.in", "first_name": "Michael", "last_name": "Lawson", "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/follettkyle/128.jpg" }, { "id": 8, "email": "lindsay.ferguson@reqres.in", "first_name": "Lindsay", "last_name": "Ferguson", "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/araa3185/128.jpg" }, { "id": 9, "email": "tobias.funke@reqres.in", "first_name": "Tobias", "last_name": "Funke", "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/vivekprvr/128.jpg" }, { "id": 10, "email": "byron.fields@reqres.in", "first_name": "Byron", "last_name": "Fields", "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/russoedu/128.jpg" }, { "id": 11, "email": "george.edwards@reqres.in", "first_name": "George", "last_name": "Edwards", "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/mrmoiree/128.jpg" }, { "id": 12, "email": "rachel.howell@reqres.in", "first_name": "Rachel", "last_name": "Howell", "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/hebertialmeida/128.jpg" } ]}io.restassured.internal.ValidatableResponseImpl@42a9a63eTests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 8.158 sec - in TestSuiteResults :Tests run: 3, Failures: 0, Errors: 0, Skipped: 0[INFO][INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ RestAssured ---[INFO] Building jar: C:\Users\Anthony\eclipse-workspace\RestAssured\target\RestAssured-0.0.1-SNAPSHOT.jar[INFO][INFO] --- maven-install-plugin:2.4:install (default-install) @ RestAssured ---Downloading from central: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0.5/plexus-utils-3.0.5.jarDownloaded from central: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0.5/plexus-utils-3.0.5.jar (230 kB at 73 kB/s)[INFO] Installing C:\Users\Anthony\eclipse-workspace\RestAssured\target\RestAssured-0.0.1-SNAPSHOT.jar to C:\Users\Anthony\.m2\repository\com\restassured\RestAssured\0.0.1-SNAPSHOT\RestAssured-0.0.1-SNAPSHOT.jar[INFO] Installing C:\Users\Anthony\eclipse-workspace\RestAssured\pom.xml to C:\Users\Anthony\.m2\repository\com\restassured\RestAssured\0.0.1-SNAPSHOT\RestAssured-0.0.1-SNAPSHOT.pom[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------[INFO] Total time: 18.018 s[INFO] Finished at: 2019-09-06T19:45:40+08:00[INFO] ------------------------------------------------------------------------C:\Users\Anthony\eclipse-workspace\RestAssured>
然后再去路径\test-output找到以时间戳命名的html报告文件。
Jenkins持续集成
这部分好说,我们在cmd可以通过命令 mvn clean install来执行用例,拿到报告,那么我们放到jenkins上,如果是自由风格的job,直接添加一个bat或者shell,把命令填进去就可以。如果是pipeline的方式,我们可以把命令保存在bat文件或者shell脚本文件,或者也是直接在pipeline中写执行mvn clean install命令。如果想要把接口服务器地址和端口这两个变量进行参数化设置,请参考我这篇文章。
这个教程的源码:
转载地址:http://fqxws.baihongyu.com/