赞
踩
前面项目已创建好,依赖包添加完成,testng也已添加
项目结构如下:
1.设计配置文件
在src/main/java下新建一个包:com.qa.config,然后在新包下新建一个config.properties文件,文件内容如下
2.加载读取properties文件
然后在src/main/java下新建一个包:com.qa.base,新建一个TestBase.java,这个类作为所有接口请求测试的父类,都需要继承这个父类,目前我们就写一个构造方法,实现加载读取properties文件。
我们不想在代码里写死例如像HTTP响应状态码200这样的硬编码,所以,这里我们在TestBase.java里把状态码给用常量写出来,方便每一个TestNG测试用例去调用去断言
package com.qa.base; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Properties; //接口请求测试的父类 public class TestBase { public Properties prop; //写一个构造函数 public TestBase() { try { prop = new Properties(); FileInputStream fis = new FileInputStream(System.getProperty("user.dir")+ "/src/main/java/com/qa/config/config.properties"); prop.load(fis); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
3. 新建一个log4j.properties文件
在Eclipse上点击当前项目名,右键new -source folder,输出src/main/config,点击确定,然后在src/main/config下新建一个log4j.properties文件,内容如下。
### set log levels ### log4j.rootLogger = INFO, stdout, file log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss SSS} %-5p %c{1}:%L - %m%n log4j.appender.file = org.apache.log4j.DailyRollingFileAppender log4j.appender.file.File = ./log/apilog.log # overwirte the old log file log4j.appender.file.Append = false ## log4j.appender.file.Threshold = INFO log4j.appender.file.layout = org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss SSS} %-5p %c{1}:%L - %m%n
在项目根目录下新建log文件夹:用于日志输出存放
新建这个文件夹是上面log4j.properties文件我们设置的日志保存文件路径是在./log文件夹下。
4.写一个JSON解析的工具类
在src/main/java下新建一个包:com.qa.util,然后在新包下创建一个TestUtil.java类。
package com.qa.util; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; public class TestUtil { /** * * @param responseJson ,这个变量是拿到响应字符串通过json转换成json对象 * @param jpath,这个jpath指的是用户想要查询json对象的值的路径写法 * jpath写法举例:1) per_page 2)data[1]/first_name ,data是一个json数组,[1]表示索引 * /first_name 表示data数组下某一个元素下的json对象的名称为first_name * @return,返回first_name这个json对象名称对应的值 */ //1 json解析方法 public static String getValueByJPath(JSONObject responseJson, String jpath){ Objectobj = responseJson; for(String s : jpath.split("/")) { if(!s.isEmpty()) { if(!(s.contains("[") || s.contains("]"))) { obj = ((JSONObject) obj).get(s); }else if(s.contains("[") || s.contains("]")) { obj =((JSONArray)((JSONObject)obj).get(s.split("\\[")[0])).get(Integer.parseInt(s.split("\\[")[1].replaceAll("]", ""))); } } } return obj.toString(); } }
简单解释下上面的代码,主要是查询两种json对象的的值,第一种最简单的,这个json对象在整个json串的第一层,例如上面截图中的per_page,这个per_page就是通过jpath这个参数传入,返回的结果就是3. 第二种jpath的查询,例如我想查询data下第一个用户信息里面的first_name的值,这个时候jpath的写法就是data[0]/first_name,查询结果应该是Eve。
4.请求方法代码封装
在src/main/java下新建一个包:com.qa.restclient,然后新建一个RestClient.java文件,下面是具体代码,已加日志输出
这个Java接口自动化测试框架的核心就是Get和POST请求方法的封装过程。
package com.qa.restclient; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.http.ParseException; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.apache.log4j.Logger; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; public class RestClient { final static Logger Log = Logger.getLogger(RestClient.class); /** * 不带请求头的get方法封装 * @param url * @return 返回响应对象 * @throws ClientProtocolException * @throws IOException */ public CloseableHttpResponse get (String url) throws ClientProtocolException, IOException { //创建一个可关闭的HttpClient对象 CloseableHttpClient httpclient = HttpClients.createDefault(); //创建一个HttpGet的请求对象 HttpGet httpget = new HttpGet(url); //执行请求,相当于postman上点击发送按钮,然后赋值给HttpResponse对象接收 Log.info("开始发送get请求..."); CloseableHttpResponse httpResponse = httpclient.execute(httpget); Log.info("发送请求成功!开始得到响应对象。"); return httpResponse; } /** * 带请求头信息的get方法 * @param url * @param headermap,键值对形式 * @return 返回响应对象 * @throws ClientProtocolException * @throws IOException */ public CloseableHttpResponse get (String url,HashMap<String,String> headermap) throws ClientProtocolException, IOException { //创建一个可关闭的HttpClient对象 CloseableHttpClient httpclient = HttpClients.createDefault(); //创建一个HttpGet的请求对象 HttpGet httpget = new HttpGet(url); //加载请求头到httpget对象 for(Map.Entry<String, String> entry : headermap.entrySet()) { httpget.addHeader(entry.getKey(), entry.getValue()); } //执行请求,相当于postman上点击发送按钮,然后赋值给HttpResponse对象接收 CloseableHttpResponse httpResponse = httpclient.execute(httpget); Log.info("开始发送带请求头的get请求..."); return httpResponse; } /** * 封装post方法 * @param url * @param entityString,其实就是设置请求json参数 * @param headermap,带请求头 * @return 返回响应对象 * @throws ClientProtocolException * @throws IOException */ public CloseableHttpResponse post (String url, String entityString, HashMap<String,String> headermap) throws ClientProtocolException, IOException { //创建一个可关闭的HttpClient对象 CloseableHttpClient httpclient = HttpClients.createDefault(); //创建一个HttpPost的请求对象 HttpPost httppost = new HttpPost(url); //设置payload httppost.setEntity(new StringEntity(entityString)); //加载请求头到httppost对象 for(Map.Entry<String, String> entry : headermap.entrySet()) { httppost.addHeader(entry.getKey(), entry.getValue()); } //发送post请求 CloseableHttpResponse httpResponse = httpclient.execute(httppost); Log.info("开始发送post请求"); return httpResponse; } /** * 封装 put请求方法,参数和post方法一样 * @param url * @param entityString,这个主要是设置payload,一般来说就是json串 * @param headerMap,带请求的头信息,格式是键值对,所以这里使用hashmap * @return 返回响应对象 * @throws ClientProtocolException * @throws IOException */ public CloseableHttpResponse put (String url, String entityString, HashMap<String,String> headerMap) throws ClientProtocolException, IOException { CloseableHttpClient httpclient = HttpClients.createDefault(); HttpPut httpput = new HttpPut(url); httpput.setEntity(new StringEntity(entityString)); for(Map.Entry<String, String> entry : headerMap.entrySet()) { httpput.addHeader(entry.getKey(), entry.getValue()); } //发送put请求 CloseableHttpResponse httpResponse = httpclient.execute(httpput); return httpResponse; } /** * 封装 delete请求方法,参数和get方法一样 * @param url, 接口url完整地址 * @return,返回一个response对象,方便进行得到状态码和json解析动作 * @throws ClientProtocolException * @throws IOException */ public CloseableHttpResponse delete (String url) throws ClientProtocolException, IOException { CloseableHttpClient httpclient = HttpClients.createDefault(); HttpDelete httpdel = new HttpDelete(url); //发送delete请求 CloseableHttpResponse httpResponse = httpclient.execute(httpdel); return httpResponse; } /** * 获取响应状态码,常用来和TestBase中定义的状态码常量去测试断言使用 * @param response * @return 返回int类型状态码 */ public int getStatusCode (CloseableHttpResponse response) { int statusCode = response.getStatusLine().getStatusCode(); Log.info("解析,得到响应状态码:"+ statusCode); return statusCode; } /** * * @param response, 任何请求返回返回的响应对象 * @return, 返回响应体的json格式对象,方便接下来对JSON对象内容解析 * 接下来,一般会继续调用TestUtil类下的json解析方法得到某一个json对象的值 * @throws ParseException * @throws IOException */ public JSONObject getResponseJson (CloseableHttpResponse response) throws ParseException, IOException { Log.info("得到响应对象的String格式"); String responseString = EntityUtils.toString(response.getEntity(),"UTF-8"); JSONObject responseJson = JSON.parseObject(responseString); Log.info("返回响应内容的JSON格式"); return responseJson; } }
5.TestNG测试用例测试get方法
在src/test/java下新建一个包:com.qa.tests,然后新建一个GetApiTest.java类,写一个TestNG的测试用例来测试下我们上面写的Get请求方法
简单提一下TestNG的断言方法,我们一般测试都需要写断言的代码,否则这样的单元测试代码就没有意义。下面,我在statusCode和json解析的first_name进行断言。
package com.qa.tests; import java.io.IOException; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.log4j.Logger; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.alibaba.fastjson.JSONObject; import com.qa.base.TestBase; import com.qa.restclient.RestClient; import com.qa.util.TestUtil; public class GetApiTest extends TestBase { TestBase testBase; String host; String url; RestClient restClient; CloseableHttpResponse closeableHttpResponse; final static Logger Log = Logger.getLogger(GetApiTest.class); @BeforeClass public void setUp() { testBase = new TestBase(); //Log.info("测试服务器地址为:"+ host.toString()); host = prop.getProperty("HOST"); //Log.info("当前测试接口的完整地址为:"+url.toString()); url = host + "/api/users?page=2"; } @Test public void getAPITest() throws ClientProtocolException, IOException { Log.info("开始执行用例..."); restClient = new RestClient(); closeableHttpResponse = restClient.get(url); //断言状态码是不是200 Log.info("测试响应状态码是否是200"); int statusCode = restClient.getStatusCode(closeableHttpResponse); Assert.assertEquals(statusCode, RESPNSE_STATUS_CODE_200, "response status code is not 200"); JSONObject responseJson = restClient.getResponseJson(closeableHttpResponse); //System.out.println("respon json from API-->" + responseJson); //json内容解析 String s = TestUtil.getValueByJPath(responseJson,"data[0]/first_name"); Log.info("执行JSON解析,解析的内容是 " + s); //System.out.println(s); Log.info("接口内容响应断言"); Assert.assertEquals(s, "Eve","first name is not Eve"); Log.info("用例执行结束..."); } }
执行日志输出如下:
经常使用的测试断言:
Assert.assertEquals(“现实结果”, “期待结果”,“断言失败时候打印日志消息”);
6.TestNG测试用例测试post方法
post接口示例:
这个接口的作用是创建用户,参数是一个json类型的数据,一个name一个job,两个JSON对象。发送请求之后,返回的JSON数据有name和job和id,以及创建时间这几个数据。
JAVA Bean类
写测试用例之前,我们需要提前准备好json数据【上边的name和job】,一般来说,在Java中JSON数据都是放在JAVA Bean类中,通过JSON把高级对象序列化成JSON对象。
在src/main/java中新建包:com.qa.data,然后新建一个Users.java,这个命名就参考接口的url单词就行。在postman或者网站该post方法,我们知道,需要name和job这两个json对象。我们新建一个bean类,同alt+shift+s,然后选择生成构造方法和set和get方法。
package com.qa.data; public class Users { private String name; private String pwd; private String srv_name; public Users() { super(); } public Users(String name, String job,String srv_name) { super(); this.name = name; this.pwd = pwd; this.srv_name = srv_name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public String getSrv_name() { return srv_name; } public void setSrv_name(String srv_name) { this.srv_name = srv_name; } }
TestNG用例测试
在src/test/java下的com.qa.tests我们新建一个POST测试用例,现在我们的TestNG测试类代码如下:
package com.qa.tests; import java.io.IOException; import java.util.HashMap; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.util.EntityUtils; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.qa.base.TestBase; import com.qa.data.Users; import com.qa.restclient.RestClient; import com.qa.util.TestUtil; public class PostApiTest extends TestBase { TestBase testBase; String host; String url; RestClient restClient; CloseableHttpResponse closeableHttpResponse; @BeforeClass public void setUp() { testBase = new TestBase(); host = prop.getProperty("HOST"); url = host + "/api/users"; } @Test public void postApiTest() throws ClientProtocolException, IOException { restClient = new RestClient(); //准备请求头信息 HashMap<String,String> headermap = new HashMap<String,String>(); headermap.put("Content-Type", "application/json"); //这个在postman中可以查询到 //对象转换成Json字符串 Users user = new Users("Anthony","tester"); String userJsonString = JSON.toJSONString(user); //System.out.println(userJsonString); closeableHttpResponse = restClient.post(url, userJsonString, headermap); //验证状态码是不是200 int statusCode = closeableHttpResponse.getStatusLine().getStatusCode(); Assert.assertEquals(statusCode, RESPNSE_STATUS_CODE_201,"status code is not 201"); //断言响应json内容中name和job是不是期待结果 String responseString = EntityUtils.toString(closeableHttpResponse.getEntity()); JSONObject responseJson = JSON.parseObject(responseString); //System.out.println(responseString); String name = TestUtil.getValueByJPath(responseJson, "name"); String job = TestUtil.getValueByJPath(responseJson, "job"); Assert.assertEquals(name, "Anthony","name is not same"); Assert.assertEquals(job, "tester","job is not same"); } }
7.TestNG测试用例测试put方法
package com.qa.tests; import java.io.IOException; import java.util.HashMap; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.util.EntityUtils; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.qa.base.TestBase; import com.qa.data.Users; import com.qa.restclient.RestClient; import com.qa.util.TestUtil; public class PutApiTest extends TestBase { TestBase testBase; String host; String url; RestClient restClient; CloseableHttpResponse closeableHttpResponse; @BeforeClass public void setUp() { testBase = new TestBase(); host = prop.getProperty("HOST"); url = host + "/api/users/2"; } @Test public void putTest() throws ClientProtocolException, IOException{ restClient = new RestClient(); HashMap<String,String> headermap = new HashMap<String,String>(); headermap.put("Content-Type", "application/json"); //这个在postman中可以查询到 //对象转换成Json字符串 Users user = new Users("Anthony","automation tester"); String userJsonString = JSON.toJSONString(user); //System.out.println(userJsonString); closeableHttpResponse = restClient.put(url, userJsonString, headermap); //验证状态码是不是200 int statusCode = closeableHttpResponse.getStatusLine().getStatusCode(); Assert.assertEquals(statusCode, RESPNSE_STATUS_CODE_200,"response status code is not 200"); //验证名称为Anthony的jon是不是 automation tester String responseString = EntityUtils.toString(closeableHttpResponse.getEntity()); JSONObject responseJson = JSON.parseObject(responseString); String jobString = TestUtil.getValueByJPath(responseJson, "job"); System.out.println(jobString); Assert.assertEquals(jobString, "automation tester","job is not same"); } }
8.TestNG测试用例测试Delete方法
package com.qa.tests; import java.io.IOException; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.qa.base.TestBase; import com.qa.restclient.RestClient; public class DeleteApiTest extends TestBase { TestBase testBase; String host; String url; RestClient restClient; CloseableHttpResponse closeableHttpResponse; @BeforeClass public void setUp() { testBase = new TestBase(); host = prop.getProperty("HOST"); url = host + "/api/users/2"; //直接在这个网站可以找到delete的api } @Test public void deleteApiTest() throws ClientProtocolException, IOException { restClient = new RestClient(); closeableHttpResponse = restClient.delete(url); int statusCode = closeableHttpResponse.getStatusLine().getStatusCode(); System.out.println(statusCode); Assert.assertEquals(statusCode, 204,"status code is not 204"); } }
源码:
链接:https://pan.baidu.com/s/1dUYQBZFJrlDSkR4EYApBUA 提取码:4RT8
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。