├── .gitignore ├── Getting started.md ├── README.md ├── config └── log4j.properties ├── jsondir ├── reponseTest.json └── requestTest.json ├── pom.xml └── src ├── main └── java │ └── com │ └── tools │ ├── apitools │ ├── ApiTools.java │ └── MyAssert.java │ ├── config │ └── LoggerControler.java │ ├── filetools │ └── ReadTxtFile.java │ └── steps │ └── Steps.java └── test ├── java └── com │ ├── apitest │ ├── ApiTest.java │ └── AssertJsonTest.java │ ├── bose │ └── apitoolstest │ │ └── LogTest.java │ ├── filetoolstest │ └── ReadTest.java │ ├── run │ └── RunnerBoseTest.java │ └── step │ └── StepDemo01.java └── resources └── demo └── englishTestCase.feature /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | target 3 | logs 4 | *.iml 5 | *.class 6 | *.log 7 | out 8 | **/.idea/** -------------------------------------------------------------------------------- /Getting started.md: -------------------------------------------------------------------------------- 1 | ## 框架实现 2 | 1. 通过引入cucumber相关包,实现支持gerkin语言编写case。 3 | 2. 引入Rest Assured 并做简要的Post 和 Get请求封装,实现Restful类型API的POST和GET请求。 4 | 3. 引入TestNG 并继承Assert,增加部分校验方式。 5 | 4. 引入log4j 完成log日志 6 | 5. 引入json-unit,完成对两个json文件的校验 7 | 8 | 9 | ## 快速入门: 10 | ### 发起Get请求step: 11 | ``` 12 | When I send a GET request to "Api URL" 13 | ``` 14 | ### 发起Post请求,不带json: 15 | ``` 16 | I send a POST request to "Api URL" 17 | ``` 18 | ### 发起带body的post请求: 19 | ``` 20 | When I send a POST request to "API URL" and request json: 21 | """ 22 | { 23 | "key1": "value1", 24 | "key2": "value2" 25 | } 26 | """ 27 | ``` 28 | *注意:不要遗漏了 : 和 """ """* 29 | ### 校验返回的状态码: 30 | ``` 31 | Then the response status should be "XXX" 32 | ``` 33 | *注意:最后的xxx 只能是3位数据* 34 | ### 校验json返回的某个值: 35 | 假设需要校验如下json中的result值是否是success: 36 | 37 | ``` 38 | { "result":"success"} 39 | ``` 40 | 41 | step写法: 42 | 43 | ``` 44 | Then the JSON response "result" equals "success" 45 | ``` 46 | 47 | 假设需要校验如下json中的rxSessionId值: 48 | 49 | step写法: 50 | 51 | ``` 52 | { 53 | "rxSessionId": "R1D9VDLN", 54 | "medicareLeadExtension": { 55 | "rxSessionId": "123" 56 | }, 57 | "leadMembers": [ 58 | { 59 | "phoneType": "1" 60 | } 61 | ], 62 | "leadMembers": [ 63 | { 64 | "phoneType": "2" 65 | } 66 | ] 67 | } 68 | ``` 69 | 70 | step写法: 71 | 72 | ``` 73 | Then the JSON response "medicareLeadExtension.rxSessionId" equals "123" 74 | ``` 75 | 76 | 3.假设同样上面的json,需要获取第一个phoneType的值并校验: 77 | 78 | step写法: 79 | 80 | ``` 81 | Then the JSON response "leadMembers[0].phoneType" equals "1" 82 | ``` 83 | 84 | ## 对返回的整个json一次性校验: 85 | 86 | step写法: 87 | 88 | ``` 89 | Then the JSON response equals 90 | """ 91 | { 92 | "result":"success" 93 | } 94 | """ 95 | ``` 96 | 97 | ### 对返回的json某个字段不为空校验: 98 | 99 | step写法: 100 | 101 | ``` 102 | Then the JSON response "jsonpath" should be not null 103 | ``` 104 | 105 | ### 对返回的json某个字段是否以XX开头校验 106 | 107 | step写法: 108 | 109 | ``` 110 | Then the JSON response "jsonpath" start with "xx" 111 | ``` 112 | 113 | ### 对返回的json某个字段是否以XX结尾校验 114 | 115 | step写法: 116 | 117 | ``` 118 | Then the JSON response "jsonpath" end with "xx" 119 | ``` 120 | 121 | ### 对返回的json某个字段是否包含xx 122 | 123 | step写法: 124 | 125 | ``` 126 | Then the JSON response "jsonpath" include "xx" 127 | ``` 128 | 129 | ### 对返回的json某个字段是否是XXX类型的校验 130 | 131 | step写法: 132 | 133 | ``` 134 | And the JSON response "jsonpath" type should be "这里是正则表达式" 135 | ``` 136 | 137 | ### 通过外部文件发起request和校验response 138 | 139 | step写法: 140 | 141 | ``` 142 | When I use a "外部文件名" file to send a POST request to "api url" 143 | Then the JSON response equals json file "外部文件名" 144 | ``` 145 | 146 | *注意:外部文件名需要放于项目结构的jsondir文件夹中,文件支持.txt和.json文件* 147 | 148 | 149 | ## feature编写注意事项: 150 | 1. 不涉及 Examples的Scenario,用Scenario关键字,设计到Examples 用Scenario Outline 关键字,如下: 151 | 152 | ![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1992590-daec06e0754bf5dd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 153 | 154 | ## Case Demo 155 | 156 | ``` 157 | Scenario Outline: use examples 158 | When I send a GET request to "paiurl" 159 | Then the response status should be "200" 160 | And the JSON response "message" include "ss" 161 | And the JSON response "message" end with "ss" 162 | And the JSON response "message" start with "su" 163 | And the JSON response "url" should be not null 164 | And the JSON response "sessionId" type should be "^\d{6}$" 165 | Then the JSON response "" equals "" 166 | Examples: 167 | | jsonPath | value | 168 | | genericPlan | false | 169 | | ehiCarrierId.carrierName | 90121100 | 170 | | ehi[0].carrierName | ha | 171 | ``` 172 | ``` 173 | Scenario: json file 174 | When I use a "requestTest.json" file to send a POST request to "postapi url" 175 | Then the response status should be "200" 176 | Then the JSON response equals json file "reponseTest.json" 177 | ``` 178 | 179 | ``` 180 | Scenario: test post request 181 | When I send a POST request to "postapi url" and request json: 182 | """ 183 | { 184 | "sessionId": 244636, 185 | "agentNotes": "notepad" 186 | } 187 | """ 188 | Then the response status should be "200" 189 | And the JSON response "result" equals "success" 190 | ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **搭建这个完全是因为之前某个团队就要这么做而搭建,然后实际API自动化测试中,非常不建议通过(Cucucmber)这种方式来实现。完全可以用rest assured + TestNG/JUnit 完成你需要的API自动化测试** 2 | 3 | # cucumber_restassured 4 | cucumber + restassured api automation 5 | 6 | ## 框架实现 7 | 1. 通过引入cucumber相关包,实现支持gerkin语言编写case。 8 | 2. 引入Rest Assured 并做简要的Post 和 Get请求封装,实现Restful类型API的POST和GET请求。 9 | 3. 引入TestNG 并继承Assert,增加部分校验方式。 10 | 4. 引入log4j 完成log日志 11 | 5. 引入json-unit,完成对两个json文件的校验 12 | 13 | 14 | ## 快速入门: 15 | ### 发起Get请求step: 16 | ``` 17 | When I send a GET request to "Api URL" 18 | ``` 19 | ### 发起Post请求,不带json: 20 | ``` 21 | I send a POST request to "Api URL" 22 | ``` 23 | ### 发起带body的post请求: 24 | ``` 25 | When I send a POST request to "API URL" and request json: 26 | """ 27 | { 28 | "key1": "value1", 29 | "key2": "value2" 30 | } 31 | """ 32 | ``` 33 | *注意:不要遗漏了 : 和 """ """* 34 | ### 校验返回的状态码: 35 | ``` 36 | Then the response status should be "XXX" 37 | ``` 38 | *注意:最后的xxx 只能是3位数据* 39 | ### 校验json返回的某个值: 40 | 假设需要校验如下json中的result值是否是success: 41 | 42 | ``` 43 | { "result":"success"} 44 | ``` 45 | 46 | step写法: 47 | 48 | ``` 49 | Then the JSON response "result" equals "success" 50 | ``` 51 | 52 | 假设需要校验如下json中的rxSessionId值: 53 | 54 | step写法: 55 | 56 | ``` 57 | { 58 | "rxSessionId": "R1D9VDLN", 59 | "medicareLeadExtension": { 60 | "rxSessionId": "123" 61 | }, 62 | "leadMembers": [ 63 | { 64 | "phoneType": "1" 65 | } 66 | ], 67 | "leadMembers": [ 68 | { 69 | "phoneType": "2" 70 | } 71 | ] 72 | } 73 | ``` 74 | 75 | step写法: 76 | 77 | ``` 78 | Then the JSON response "medicareLeadExtension.rxSessionId" equals "123" 79 | ``` 80 | 81 | 3.假设同样上面的json,需要获取第一个phoneType的值并校验: 82 | 83 | step写法: 84 | 85 | ``` 86 | Then the JSON response "leadMembers[0].phoneType" equals "1" 87 | ``` 88 | 89 | ## 对返回的整个json一次性校验: 90 | 91 | step写法: 92 | 93 | ``` 94 | Then the JSON response equals 95 | """ 96 | { 97 | "result":"success" 98 | } 99 | """ 100 | ``` 101 | 102 | ### 对返回的json某个字段不为空校验: 103 | 104 | step写法: 105 | 106 | ``` 107 | Then the JSON response "jsonpath" should be not null 108 | ``` 109 | 110 | ### 对返回的json某个字段是否以XX开头校验 111 | 112 | step写法: 113 | 114 | ``` 115 | Then the JSON response "jsonpath" start with "xx" 116 | ``` 117 | 118 | ### 对返回的json某个字段是否以XX结尾校验 119 | 120 | step写法: 121 | 122 | ``` 123 | Then the JSON response "jsonpath" end with "xx" 124 | ``` 125 | 126 | ### 对返回的json某个字段是否包含xx 127 | 128 | step写法: 129 | 130 | ``` 131 | Then the JSON response "jsonpath" include "xx" 132 | ``` 133 | 134 | ### 对返回的json某个字段是否是XXX类型的校验 135 | 136 | step写法: 137 | 138 | ``` 139 | And the JSON response "jsonpath" type should be "这里是正则表达式" 140 | ``` 141 | 142 | ### 通过外部文件发起request和校验response 143 | 144 | step写法: 145 | 146 | ``` 147 | When I use a "外部文件名" file to send a POST request to "api url" 148 | Then the JSON response equals json file "外部文件名" 149 | ``` 150 | 151 | *注意:外部文件名需要放于项目结构的jsondir文件夹中,文件支持.txt和.json文件* 152 | 153 | 154 | ## feature编写注意事项: 155 | 1. 不涉及 Examples的Scenario,用Scenario关键字,设计到Examples 用Scenario Outline 关键字,如下: 156 | 157 | ![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1992590-daec06e0754bf5dd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 158 | 159 | ## Case Demo 160 | 161 | ``` 162 | Scenario Outline: use examples 163 | When I send a GET request to "paiurl" 164 | Then the response status should be "200" 165 | And the JSON response "message" include "ss" 166 | And the JSON response "message" end with "ss" 167 | And the JSON response "message" start with "su" 168 | And the JSON response "url" should be not null 169 | And the JSON response "sessionId" type should be "^\d{6}$" 170 | Then the JSON response "" equals "" 171 | Examples: 172 | | jsonPath | value | 173 | | genericPlan | false | 174 | | ehiCarrierId.carrierName | 90121100 | 175 | | ehi[0].carrierName | ha | 176 | ``` 177 | ``` 178 | Scenario: json file 179 | When I use a "requestTest.json" file to send a POST request to "postapi url" 180 | Then the response status should be "200" 181 | Then the JSON response equals json file "reponseTest.json" 182 | ``` 183 | 184 | ``` 185 | Scenario: test post request 186 | When I send a POST request to "postapi url" and request json: 187 | """ 188 | { 189 | "sessionId": 244636, 190 | "agentNotes": "notepad" 191 | } 192 | """ 193 | Then the response status should be "200" 194 | And the JSON response "result" equals "success" 195 | ``` 196 | 197 | ## 通过Junit 运行feature. 198 | 1. 在Pom.xml 文件添加junit相关包: 199 | ``` 200 | 201 | info.cukes 202 | cucumber-junit 203 | 1.2.4 204 | test 205 | 206 | 207 | 208 | junit 209 | junit 210 | 4.12 211 | test 212 | 213 | ``` 214 | 2. 新建个运行类,代码例子如下: 215 | 216 | ``` 217 | import cucumber.api.CucumberOptions; 218 | import cucumber.api.junit.Cucumber; 219 | import org.junit.runner.RunWith; 220 | 221 | @RunWith(Cucumber.class) 222 | @CucumberOptions( 223 | strict = true, 224 | monochrome = true, 225 | plugin = {"pretty", "html:target/cucumber", "json:target/cucumber.json"}, 226 | features = {"src/test/java/bosev2"}, 227 | glue = {"com.bose.step"}, 228 | tags = {"~@unimplemented"}) 229 | public class RunnerBoseTest { 230 | } 231 | ``` 232 | 233 | @RunWith(Cucumber.class) : 注解表示通过Cucumber的Junit 方式运行脚本 234 | @CucumberOptions () :注解用于配置运行信息,其中代码中的plugin 表示测试报告输出的路径和格式, feature 表示被运行的feature文件的包路径, glue中配置steps的包路径地址,tags中配置要运行的用例的tags名,其实~符号表示除了这个tags的所有tags. 235 | 236 | ## 通过Jenkins 执行 237 | 1. 在Pom.xml 文件里面添加运行插件,如下: 238 | ``` 239 | 240 | 241 | 242 | org.apache.maven.plugins 243 | maven-compiler-plugin 244 | 3.3 245 | true 246 | 247 | 1.7 248 | 1.7 249 | UTF-8 250 | 251 | 252 | 253 | 254 | org.apache.maven.plugins 255 | maven-surefire-plugin 256 | 2.18.1 257 | 258 | false 259 | 260 | 261 | 262 | 263 | ``` 264 | 2. 在Jenkins 中添加[Cucumber-JVM reports](https://github.com/jenkinsci/cucumber-reports-plugin)插件。 265 | 3. 新建Maven job,配置maven构建方式和构建后的测试报告展示。 266 | 267 | ![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1992590-918aec8401020427.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 268 | 269 | Cucumber-JVM reports 提供了非常漂亮的report,如下: 270 | 271 | ![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1992590-6f22e647b4eed391.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 272 | -------------------------------------------------------------------------------- /config/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=DEBUG, stdout, logfile 2 | 3 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 4 | log4j.appender.stdout.Target = System.out 5 | log4j.appender.stdout.Threshold=info 6 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 7 | log4j.appender.stdout.encoding=UTF-8 8 | log4j.appender.stdout.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} %p %t [%c]%M(line:%L)%m%n 9 | 10 | log4j.appender.logfile.encoding=UTF-8 11 | log4j.appender.logfile=org.apache.log4j.FileAppender 12 | log4j.appender.logfile.File=logs/log.log 13 | log4j.appender.logfile.Threshold=info 14 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 15 | log4j.appender.logfile.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} %p %t [%c]%M(line:%L)%m%n -------------------------------------------------------------------------------- /jsondir/reponseTest.json: -------------------------------------------------------------------------------- 1 | { 2 | "session": { 3 | "scriptId": 1, 4 | "version": 9, 5 | "sessionId": 244357, 6 | "pageNum": 1, 7 | "scriptTitle": "Medicare Inbound", 8 | "highestPageSubmitted": 6, 9 | "status": "C" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /jsondir/requestTest.json: -------------------------------------------------------------------------------- 1 | { 2 | "session": { 3 | "scriptId": 1, 4 | "version": 9, 5 | "sessionId": 244357, 6 | "pageNum": 1, 7 | "scriptTitle": "Medicare Inbound", 8 | "highestPageSubmitted": 6, 9 | "status": "C" 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | Automation 8 | ApiFramework 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | 14 | 15 | info.cukes 16 | cucumber-java8 17 | 1.2.4 18 | test 19 | 20 | 21 | 22 | info.cukes 23 | cucumber-java 24 | 1.2.4 25 | 26 | 27 | 28 | 29 | info.cukes 30 | cucumber-html 31 | 0.2.3 32 | 33 | 34 | 35 | 36 | 37 | com.jayway.restassured 38 | rest-assured 39 | 2.9.0 40 | 41 | 42 | 43 | 44 | org.testng 45 | testng 46 | 6.9.10 47 | 48 | 49 | 50 | 51 | log4j 52 | log4j 53 | 1.2.17 54 | 55 | 56 | 57 | org.slf4j 58 | slf4j-log4j12 59 | 1.7.5 60 | provided 61 | 62 | 63 | 64 | 65 | net.javacrumbs.json-unit 66 | json-unit 67 | 1.13.0 68 | 69 | 70 | 71 | 72 | com.fasterxml.jackson.core 73 | jackson-databind 74 | 2.8.1 75 | 76 | 77 | 78 | info.cukes 79 | cucumber-junit 80 | 1.2.4 81 | test 82 | 83 | 84 | 85 | junit 86 | junit 87 | 4.12 88 | test 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | org.apache.maven.plugins 99 | maven-compiler-plugin 100 | 3.3 101 | true 102 | 103 | 1.7 104 | 1.7 105 | UTF-8 106 | 107 | 108 | 109 | 110 | org.apache.maven.plugins 111 | maven-surefire-plugin 112 | 2.18.1 113 | 114 | false 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /src/main/java/com/tools/apitools/ApiTools.java: -------------------------------------------------------------------------------- 1 | package com.tools.apitools; 2 | 3 | import com.jayway.restassured.response.Response; 4 | import com.tools.config.LoggerControler; 5 | import org.testng.annotations.Test; 6 | 7 | import static com.jayway.restassured.RestAssured.given; 8 | 9 | /** 10 | * Created by vidorh on 7/28/2016. 11 | */ 12 | public class ApiTools { 13 | static LoggerControler log = LoggerControler.getLogger(ApiTools.class); 14 | 15 | /** 16 | * 带json的post请求 17 | * 18 | * @param apiPath api地址 19 | * @param json 请求json 20 | * @return api返回的Response 21 | */ 22 | public static Response post(String apiPath, String json) { 23 | // 开始发起post 请求 24 | Response response = given(). 25 | contentType("application/json;charset=UTF-8"). 26 | headers("headers1", "value1", "headers2", "values2"). 27 | cookies("cookies1", "values1", "cookies2", "values2"). 28 | body(json). 29 | when().log().all().post(apiPath.trim()); 30 | log.info(response.statusCode()); 31 | log.info("reponse:"); 32 | response.getBody().prettyPrint(); 33 | return response; 34 | } 35 | 36 | /** 37 | * 非json形式的post请求 38 | * 39 | * @param apiPath api地址 40 | * @return api返回 41 | */ 42 | public static Response post(String apiPath) { 43 | // Cookie someCookie = new Cookie.Builder("JSESSIONID", jsessionid).setSecured(true).setComment("some comment").build(); 44 | Response response = given(). 45 | contentType("application/json;charset=UTF-8"). 46 | headers("headers1", "value1", "headers2", "values2"). 47 | cookies("cookies1", "values1", "cookies2", "values2"). 48 | when().log().all().post(apiPath.trim()); 49 | log.info(response.statusCode()); 50 | log.info("reponse:"); 51 | response.getBody().prettyPrint(); 52 | return response; 53 | } 54 | 55 | /** 56 | * get 请求 57 | * 58 | * @param apiPath api路径 59 | * @return api的response 60 | */ 61 | public static Response get(String apiPath) { 62 | Response response = given(). 63 | contentType("application/json;charset=UTF-8"). 64 | headers("headers1", "value1", "headers2", "values2"). 65 | cookies("cookies1", "values1", "cookies2", "values2"). 66 | when().log().all().get(apiPath.trim()); 67 | log.info(response.statusCode()); 68 | log.info("reponse:"); 69 | response.getBody().prettyPrint(); 70 | return response; 71 | } 72 | 73 | @Test 74 | public void testGet(){ 75 | Response response = ApiTools.get("xxxxxxxxxx"); 76 | log.info(response); 77 | } 78 | 79 | 80 | /** 81 | * 获取json中某个key值 82 | * 83 | * @param response 接口返回 84 | * @param jsonPath jsonpath, 例如 a.b.c a.b[1].c a 85 | * @return 86 | */ 87 | public static String getJsonPathValue(Response response, String jsonPath) { 88 | String reponseJson = String.valueOf(response.jsonPath().get(jsonPath)); 89 | // String jsonValue = String.valueOf(from(reponseJson).get(jsonPath)); 90 | return reponseJson; 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/tools/apitools/MyAssert.java: -------------------------------------------------------------------------------- 1 | package com.tools.apitools; 2 | 3 | 4 | import com.tools.config.LoggerControler; 5 | import org.testng.Assert; 6 | 7 | import java.util.regex.Pattern; 8 | 9 | /** 10 | * Created by vidorh on 8/1/2016. 11 | *

12 | * 居于Testng Assert类二次封装,添加办法校验方式 13 | */ 14 | public class MyAssert extends Assert { 15 | static final LoggerControler logger = LoggerControler.getLogger(MyAssert.class); 16 | 17 | // 而外添加的校验方法 ======================================================================= 18 | 19 | /** 20 | * 断言字符是否已某个字符串开头 21 | * 22 | * @param message 断言错误消息 23 | * @param content 待断言字符串 24 | * @param prefix 前缀表达式 25 | */ 26 | public static void assertStartWith(String content, String prefix, String message) { 27 | if (message != null) 28 | logger.info(message); 29 | if (content.startsWith(prefix)) { 30 | logger.info("前缀匹配校验成功"); 31 | } else { 32 | logger.error("前缀匹配校验失败!\n待校验的字符窜为:" + content + "\n校验的前缀表达式为:" + prefix); 33 | MyAssert.fail(); 34 | } 35 | } 36 | 37 | /** 38 | * 断言字符是否已某个字符串开头 39 | * 40 | * @param content 待断言字符串 41 | * @param prefix 前缀表达式 42 | */ 43 | public static void assertStartWith(String content, String prefix) { 44 | MyAssert.assertStartWith(content, prefix, null); 45 | } 46 | 47 | /** 48 | * 断言字符是否已某个字符串结尾 49 | * 50 | * @param message 断言错误消息 51 | * @param content 待断言字符串 52 | * @param endfix 前缀表达式 53 | */ 54 | public static void assertEndWith(String content, String endfix, String message) { 55 | if (message != null) 56 | logger.info(message); 57 | if (content.endsWith(endfix)) { 58 | logger.info("后缀匹配校验成功!"); 59 | } else { 60 | logger.error("后缀匹配校验失败!\n待校验的字符窜为:" + content + "\n校验的后缀表达式为:" + endfix); 61 | MyAssert.fail(); 62 | } 63 | } 64 | 65 | /** 66 | * 断言字符是否已某个字符串结尾 67 | * 68 | * @param content 待断言字符串 69 | * @param endfix 前缀表达式 70 | */ 71 | public static void assertEndWith(String content, String endfix) { 72 | MyAssert.assertEndWith(content, endfix, null); 73 | } 74 | 75 | /** 76 | * 根据正则表达式断言是否匹配 77 | * 78 | * @param message 断言错误信息 79 | * @param matcher 待校验的字符串 80 | * @param regex 校验的正则表达式 81 | */ 82 | public static void assertMatch(String matcher, String regex, String message) { 83 | if (message != null) 84 | logger.info(message); 85 | if (Pattern.matches(regex, matcher)) { 86 | logger.info("匹配校验成功!"); 87 | } else { 88 | logger.error("匹配校验失败!\n待校验的字符串为:" + matcher + "\n校验的正则表达式为:" + regex); 89 | MyAssert.fail(); 90 | } 91 | } 92 | 93 | /** 94 | * 根据正则表达式断言是否匹配 95 | * 96 | * @param matcher 待校验的字符串 97 | * @param regex 校验的正则表达式 98 | */ 99 | public static void assertMatch(String matcher, String regex) { 100 | MyAssert.assertMatch(matcher, regex, null); 101 | } 102 | 103 | /** 104 | * 根据正则表达式断言是否匹配 105 | * 106 | * @param message 断言错误信息 107 | * @param matcher 待校验的字符串 108 | * @param regex 校验的正则表达式 109 | */ 110 | public static void assertNoMatch(String matcher, String regex, String message) { 111 | if (message != null) 112 | logger.info(message); 113 | if (!Pattern.matches(regex, matcher)) { 114 | logger.info("匹配校验成功!"); 115 | } else { 116 | logger.error("匹配校验失败!\n待校验的字符串为:" + matcher + "\n校验的正则表达式为:" + regex); 117 | MyAssert.fail(); 118 | } 119 | } 120 | 121 | /** 122 | * 根据正则表达式断言是否匹配 123 | * 124 | * @param matcher 待校验的字符串 125 | * @param regex 校验的正则表达式 126 | */ 127 | public static void assertNoMatch(String matcher, String regex) { 128 | MyAssert.assertNoMatch(matcher, regex, null); 129 | } 130 | 131 | /** 132 | * 断言字符串中是否包含某些字符 133 | * 134 | * @param message 断言错误消息 135 | * @param content 断言的字符串为 136 | * @param included 包含的字符串 137 | */ 138 | public static void assertInclude(String content, String included, String message) { 139 | if (message != null) 140 | logger.info(message); 141 | if (content.contains(included)) { 142 | logger.info("匹配校验成功!"); 143 | } else { 144 | logger.error("匹配校验失败!\n待校验的字符串为:" + content + "\n包含字符串为:" + included); 145 | MyAssert.fail(message); 146 | } 147 | } 148 | 149 | /** 150 | * 断言字符串中是否包含某些字符 151 | * 152 | * @param content 断言的字符串为 153 | * @param included 包含的字符串 154 | */ 155 | public static void assertInclude(String content, String included) { 156 | MyAssert.assertInclude(content, included, null); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/main/java/com/tools/config/LoggerControler.java: -------------------------------------------------------------------------------- 1 | package com.tools.config; 2 | 3 | import org.apache.log4j.Logger; 4 | import org.apache.log4j.PropertyConfigurator; 5 | 6 | import java.io.File; 7 | import java.io.FileInputStream; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.util.Properties; 11 | 12 | /** 13 | * Created by vidorh on 7/28/2016. 14 | */ 15 | public class LoggerControler { 16 | private static Logger logger = null; 17 | private static LoggerControler logg = null; 18 | 19 | public static LoggerControler getLogger(Class T) { 20 | if (logger == null) { 21 | // 实例化一个 Properties 类,处理log4j.Properties文件 22 | Properties props = new Properties(); 23 | try { 24 | // 获取log4j配置文件路径 25 | String envPaht = System.getProperty("user.dir") + 26 | File.separator + "config" + File.separator + "log4j.properties"; 27 | InputStream is = new FileInputStream(envPaht); 28 | props.load(is); 29 | } catch (IOException e) { 30 | e.printStackTrace(); 31 | } 32 | // log4j 的PropertyConfigurator 类的configure方法输入数据流 33 | PropertyConfigurator.configure(props); 34 | logger = Logger.getLogger(T); 35 | logg = new LoggerControler(); 36 | } 37 | return logg; 38 | } 39 | 40 | /** 41 | * 重写logger方法 42 | */ 43 | public void info(Object msg) { 44 | logger.info(msg); 45 | } 46 | 47 | public void debug(Object msg) { 48 | logger.debug(msg); 49 | } 50 | 51 | public void warn(Object msg) { 52 | logger.warn(msg); 53 | } 54 | 55 | public void error(Object msg) { 56 | logger.error(msg); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/tools/filetools/ReadTxtFile.java: -------------------------------------------------------------------------------- 1 | package com.tools.filetools; 2 | 3 | import com.tools.config.LoggerControler; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.File; 7 | import java.io.FileInputStream; 8 | import java.io.InputStreamReader; 9 | 10 | /** 11 | * Created by vidorh on 8/2/2016. 12 | */ 13 | public class ReadTxtFile { 14 | static final LoggerControler logger = LoggerControler.getLogger(ReadTxtFile.class); 15 | static String path = System.getProperty("user.dir") + File.separator + "jsondir" + File.separator; 16 | 17 | public static String readTxtFile(String fileName) { 18 | String lineTxt = null; 19 | StringBuffer stringBuffer = null; 20 | try { 21 | File file = new File(path + fileName); 22 | //判断文件是否存在 23 | if (file.isFile() && file.exists()) { 24 | InputStreamReader read = new InputStreamReader(new FileInputStream(file), "UTF-8"); 25 | BufferedReader bufferedReader = new BufferedReader(read); 26 | stringBuffer = new StringBuffer(); 27 | while ((lineTxt = bufferedReader.readLine()) != null) { 28 | stringBuffer.append(lineTxt); 29 | // System.out.println(lineTxt); 30 | } 31 | // logger.info(stringBuffer); 32 | read.close(); 33 | } else { 34 | logger.error("找不到指定的文件"); 35 | } 36 | } catch (Exception e) { 37 | logger.error("读取文件内容出错"); 38 | e.printStackTrace(); 39 | } 40 | return String.valueOf(stringBuffer); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/tools/steps/Steps.java: -------------------------------------------------------------------------------- 1 | package com.tools.steps; 2 | 3 | import com.jayway.restassured.response.Response; 4 | import com.tools.apitools.ApiTools; 5 | import com.tools.apitools.MyAssert; 6 | import com.tools.filetools.ReadTxtFile; 7 | import cucumber.api.java.en.Then; 8 | import cucumber.api.java.en.When; 9 | 10 | import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; 11 | 12 | /** 13 | * Created by vidorh on 8/1/2016. 14 | *

15 | * Steps 集合 16 | */ 17 | public class Steps { 18 | 19 | Response response = null; 20 | 21 | @When("^I send a GET request to \"(.*?)\"$") 22 | public void getRequest(String path) { 23 | response = ApiTools.get(path); 24 | } 25 | 26 | @When("^I send a POST request to \"(.*?)\"$") 27 | public void postRequest(String apiPath) throws Throwable { 28 | response = ApiTools.post(apiPath); 29 | } 30 | 31 | @When("^I send a POST request to \"(.*?)\" and request json:$") 32 | public void postRequestWithJson(String apiPath, String json) { 33 | response = ApiTools.post(apiPath, json); 34 | } 35 | 36 | @When("^I use a \"(.*?)\" file to send a POST request to \"(.*?)\"$") 37 | public void postRequestWihtFile(String fileName, String path) { 38 | String json = ReadTxtFile.readTxtFile(fileName); 39 | response = ApiTools.post(path, json); 40 | } 41 | 42 | @Then("^the JSON response equals$") 43 | public void assertResponseJson(String expected) { 44 | String responseJson = response.body().asString(); 45 | assertJsonEquals(responseJson, expected); 46 | } 47 | 48 | @Then("^the JSON response equals json file \"(.*?)\"$") 49 | public void theJSONResponseEqualsJsonFile(String fileName) { 50 | String responseJson = response.body().asString(); 51 | String fileJson = ReadTxtFile.readTxtFile(fileName); 52 | assertJsonEquals(responseJson, fileJson); 53 | } 54 | 55 | @Then("^the response status should be \"(\\d{3})\"$") 56 | public void assertStatusCode(int statusCode) { 57 | Object jsonResponse = response.getStatusCode(); 58 | MyAssert.assertEquals(jsonResponse, statusCode); 59 | } 60 | 61 | @Then("^the JSON response \"(.*?)\" equals \"(.*?)\"$") 62 | public void assertEquals(String str, String expected) { 63 | String jsonValue = ApiTools.getJsonPathValue(response, str); 64 | MyAssert.assertEquals(jsonValue, expected); 65 | } 66 | 67 | @Then("^the JSON response \"(.*?)\" type should be \"(.*?)\"$") 68 | public void assertMatch(String str, String match) { 69 | String jsonValue = ApiTools.getJsonPathValue(response, str); 70 | MyAssert.assertMatch(jsonValue, match); 71 | } 72 | 73 | @Then("^the JSON response \"(.*?)\" should be not null$") 74 | public void assertNotNull(String str) { 75 | String jsonValue = ApiTools.getJsonPathValue(response, str); 76 | MyAssert.assertNotNull(jsonValue); 77 | } 78 | 79 | @Then("^the JSON response \"(.*?)\" start with \"(.*?)\"$") 80 | public void assertStartWith(String str, String start) { 81 | String jsonValue = ApiTools.getJsonPathValue(response, str); 82 | MyAssert.assertStartWith(jsonValue, start); 83 | } 84 | 85 | @Then("^the JSON response \"(.*?)\" end with \"(.*?)\"$") 86 | public void assertEndWith(String str, String end) { 87 | String jsonValue = ApiTools.getJsonPathValue(response, str); 88 | MyAssert.assertEndWith(jsonValue, end); 89 | } 90 | 91 | @Then("^the JSON response \"(.*?)\" include \"(.*?)\"$") 92 | public void assertInclude(String str, String include) { 93 | String jsonValue = ApiTools.getJsonPathValue(response, str); 94 | MyAssert.assertInclude(jsonValue, include); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/test/java/com/apitest/ApiTest.java: -------------------------------------------------------------------------------- 1 | package com.apitest; 2 | 3 | import com.tools.apitools.ApiTools; 4 | 5 | import com.jayway.restassured.response.Response; 6 | import com.tools.apitools.MyAssert; 7 | import org.testng.annotations.Test; 8 | 9 | /** 10 | * Created by vidorh on 7/28/2016. 11 | */ 12 | public class ApiTest { 13 | 14 | 15 | @Test 16 | public void postTest01() { 17 | String path = "xxxxxx"; 18 | Response response = ApiTools.post(path); 19 | 20 | String json = response.jsonPath().get("message"); 21 | System.out.println(json); 22 | } 23 | 24 | @Test 25 | public void postTest02() { 26 | String path = "xxxxx"; 27 | String json = "{\"sessionId\":244636,\"agentNotes\":\"notepad\"}"; 28 | Response response = ApiTools.post(path, json); 29 | response.body().print(); 30 | } 31 | 32 | @Test 33 | public void postTest03() { 34 | String path = "xxxxxxx"; 35 | Response response = ApiTools.post(path); 36 | 37 | } 38 | 39 | 40 | @Test 41 | public void getTest01() { 42 | String path = "xxxxxx"; 43 | Response response = ApiTools.get(path); 44 | response.getBody().jsonPath().get("ehiCarrierId").equals(90121100); 45 | } 46 | 47 | @Test 48 | public void assertTest() { 49 | String a = "{\n" + 50 | "\"result\": \"success\"\n" + 51 | "}"; 52 | String b = "{\n" + 53 | "\"result\": \"success\"\n" + 54 | "}"; 55 | 56 | MyAssert.assertEquals(a, b); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/com/apitest/AssertJsonTest.java: -------------------------------------------------------------------------------- 1 | package com.apitest; 2 | 3 | import net.javacrumbs.jsonunit.JsonAssert; 4 | import org.testng.annotations.Test; 5 | 6 | import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; 7 | 8 | /** 9 | * Created by vidorh on 8/3/2016. 10 | */ 11 | public class AssertJsonTest { 12 | 13 | @Test 14 | public void assertJsonTest(){ 15 | assertJsonEquals("{\"test\":1}", "{\n\"test\": 12\n}"); 16 | } 17 | 18 | @Test 19 | public void assertJsonTest01(){ 20 | String json1 ="{\n" + 21 | " \"array\": [\n" + 22 | " 1,\n" + 23 | " 2,\n" + 24 | " 3\n" + 25 | " ],\n" + 26 | " \"boolean\": true,\n" + 27 | " \"null\": null,\n" + 28 | " \"number\": 123,\n" + 29 | " \"object\": {\n" + 30 | " \"a\": \"b\",\n" + 31 | " \"c\": \"d\",\n" + 32 | " \"e\": \"f\"\n" + 33 | " },\n" + 34 | " \"string\": \"Hello World\"\n" + 35 | "}"; 36 | 37 | String json2 ="{\n" + 38 | " \"array\": [\n" + 39 | " 1,\n" + 40 | " 2,\n" + 41 | " 3\n" + 42 | " ],\n" + 43 | " \"boolean\": true,\n" + 44 | " \"null\": null,\n" + 45 | " \"number\": 123,\n" + 46 | " \"object\": {\n" + 47 | " \"a\": \"b\",\n" + 48 | " \"c\": \"f\",\n" + 49 | " \"e\": \"f\"\n" + 50 | " },\n" + 51 | " \"string\": \"Hello World\"\n" + 52 | "}"; 53 | JsonAssert.assertJsonPartEquals(json1,json2,"object.c"); 54 | } 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/com/bose/apitoolstest/LogTest.java: -------------------------------------------------------------------------------- 1 | package com.bose.apitoolstest; 2 | 3 | import com.tools.config.LoggerControler; 4 | import org.testng.annotations.Test; 5 | 6 | /** 7 | * Created by vidorh on 7/28/2016. 8 | */ 9 | public class LogTest { 10 | final static LoggerControler log = LoggerControler.getLogger(LogTest.class); 11 | 12 | @Test 13 | public void testLog(){ 14 | log.info("this is info"); 15 | log.debug("this is info"); 16 | 17 | log.error("this is info"); 18 | log.warn("this is info"); 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/filetoolstest/ReadTest.java: -------------------------------------------------------------------------------- 1 | package com.filetoolstest; 2 | 3 | import com.tools.filetools.ReadTxtFile; 4 | 5 | import org.testng.annotations.Test; 6 | 7 | import static com.jayway.restassured.path.json.JsonPath.from; 8 | 9 | /** 10 | * Created by vidorh on 8/2/2016. 11 | */ 12 | public class ReadTest { 13 | @Test 14 | public void testRead() { 15 | 16 | String text = ReadTxtFile.readTxtFile("requestTest.json"); 17 | System.out.print(text); 18 | } 19 | 20 | @Test 21 | public void testJson(){ 22 | String json = ReadTxtFile.readTxtFile("reponseTest.json"); 23 | String a = from(json).get("data.application.context_data.enter_when"); 24 | System.out.println(a); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/run/RunnerBoseTest.java: -------------------------------------------------------------------------------- 1 | package com.run; 2 | 3 | import cucumber.api.CucumberOptions; 4 | import cucumber.api.junit.Cucumber; 5 | import org.junit.runner.RunWith; 6 | 7 | /** 8 | * Created by vidorh on 8/18/2016. 9 | */ 10 | 11 | @RunWith(Cucumber.class) 12 | @CucumberOptions( 13 | strict = true, 14 | monochrome = true, 15 | plugin = {"pretty", "html:target/cucumber", "json:target/cucumber.json"}, 16 | features={"src/test/resources/demo"}, 17 | glue = {"com.tools.steps"}, 18 | tags = {"~@unimplemented"}) 19 | public class RunnerBoseTest { 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/step/StepDemo01.java: -------------------------------------------------------------------------------- 1 | /* 2 | package com.step; 3 | 4 | import cucumber.api.java.zh_cn.假如; 5 | 6 | */ 7 | /** 8 | * Created by vidorh on 7/27/2016. 9 | *//* 10 | 11 | public class StepDemo01 { 12 | 13 | @假如("^我用Get请求<(.*?)>$") 14 | public void getTest(String arg1) throws Throwable { 15 | System.out.println("输出假如"+arg1); 16 | } 17 | 18 | @假如("^我输出一段文字$") 19 | public void I_visit_google() throws Throwable { 20 | System.out.println("我是假如"); 21 | } 22 | 23 | } 24 | */ 25 | -------------------------------------------------------------------------------- /src/test/resources/demo/englishTestCase.feature: -------------------------------------------------------------------------------- 1 | Feature: cucumber API Demo 2 | 3 | 4 | @fullRegression 5 | Scenario Outline:test get request 6 | When I send a GET request to "XXXXXX" 7 | Then the response status should be "200" 8 | # 校验返回json的某个字段值为XXX 9 | Then the JSON response "genericPlan" equals "false" 10 | Examples: 11 | | id | 12 | | 1469513209147 | 13 | | 1469513209148 | 14 | 15 | @fullRegression 16 | Scenario:test get request111 17 | When I send a GET request to "XXXXXX" 18 | Then the response status should be "200" 19 | # 校验返回json的某个字段值为XXX 20 | Then the JSON response "genericPlan" equals "false" 21 | Then the JSON response "ehiCarrierId" equals "90121100" 22 | Then the JSON response "carrierName" equals "Anthem Blue Cross" 23 | 24 | @fullRegression 25 | Scenario Outline: use examples 26 | When I send a GET request to "XXXXXXX" 27 | Then the response status should be "200" 28 | Then the JSON response "" equals "" 29 | Examples: 30 | | jsonPath | value | 31 | | genericPlan | false | 32 | | ehiCarrierId | 90121100 | 33 | | carrierName | Anthem Blue Cross | 34 | 35 | 36 | @sanity 37 | Scenario: test post request 38 | When I send a POST request to "XXXXXXXX" 39 | Then the response status should be "200" 40 | And the JSON response "message" equals "success" 41 | # 校验放回值是否是某种类型 42 | And the JSON response "sessionId" type should be "^\d{6}$" 43 | # 校验返回值不为空 44 | And the JSON response "url" should be not null 45 | # 校验是否以XX开头 46 | Then the JSON response "message" start with "su" 47 | # 校验是否以XX开头 48 | Then the JSON response "message" end with "ss" 49 | # 校验是否以XX开头 50 | Then the JSON response "message" include "ss" 51 | 52 | 53 | @unimplemented 54 | Scenario: test post request 55 | When I send a POST request to "XXXXX" and request json: 56 | """ 57 | { 58 | "sessionId": 244636, 59 | "agentNotes": "notepad" 60 | } 61 | """ 62 | Then the response status should be "200" 63 | And the JSON response "result" equals "success" 64 | 65 | 66 | @unimplemented 67 | Scenario: test post request 68 | When I send a POST request to "XXXXX" and request json: 69 | """ 70 | { 71 | "sessionId": 244636, 72 | "agentNotes": "notepad" 73 | } 74 | """ 75 | Then the response status should be "200" 76 | # 校验返回json是否为XXX,对整个返回json的校验 77 | Then the JSON response equals 78 | """ 79 | { 80 | "result":"success" 81 | } 82 | """ 83 | 84 | @unimplemented 85 | Scenario: 返回的json直接跟某文件校验对比 86 | When I use a "requestTest.json" file to send a POST request to "XXXXX" 87 | Then the response status should be "200" 88 | Then the JSON response equals json file "reponseTest.json" 89 | And the JSON response "data.application.context_data.enter_when" equals "2016/07/25 23:06:45 -0700" 90 | 91 | --------------------------------------------------------------------------------