NỘI DUNG BÀI HỌC
1. Khai báo các giá trị config trong properties file
configs.properties
AUTHOR = Anh Tester
USERNAME = anhtester
PASSWORD = Demo@123
BASE_URI = https://api.anhtester.com/api
BASE_PATH = /
2. Xây dựng class ConfigsGlobal để truy xuất data từ properties
ConfigsGlobal
package com.anhtester.globals;
import com.anhtester.helpers.PropertiesHelper;
public class ConfigsGlobal {
public static String BASE_URI = PropertiesHelper.getValue("BASE_URI");
public static String BASE_PATH = PropertiesHelper.getValue("BASE_PATH");
public static String USERNAME = PropertiesHelper.getValue("USERNAME");
public static String PASSWORD = PropertiesHelper.getValue("PASSWORD");
public static int TCS_TOTAL;
public static int PASSED_TOTAL;
public static int FAILED_TOTAL;
}
3. Xây dựng class lưu trữ TOKEN toàn cục
Chổ này chúng ta khai báo class mới hoặc có thể khai báo chung class ConfigsGlobal luôn cũng được.
TokenGlobal
package com.anhtester.globals;
public class TokenGlobal {
public static String TOKEN;
public static String getBearerToken() {
return TOKEN;
}
}
4. Xây dựng class lưu trữ các EndPoint của tất cả API
EndPointGlobal
package com.anhtester.globals;
public class EndPointGlobal {
public static final String EP_LOGIN = "/login";
public static final String EP_REGISTER = "/register";
public static final String EP_CATEGORY = "/category";
}
5. Xây dựng class thiết lập sẵn các hàm Request và Respone
Mục đích là giảm thiểu code khai báo phần Request và Response lại trong từng test cases. Và chúng ta có thể thiết lập sẵn các thông số đầu vào tại phần request.
SpecBuilder
package com.anhtester.keywords;
import com.anhtester.globals.ConfigsGlobal;
import com.anhtester.globals.TokenGlobal;
import com.anhtester.utils.LogUtils;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.filter.log.LogDetail;
import io.restassured.filter.log.RequestLoggingFilter;
import io.restassured.filter.log.ResponseLoggingFilter;
import io.restassured.http.ContentType;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
public class SpecBuilder {
public static RequestSpecification getRequestSpecBuilder() {
return new RequestSpecBuilder().
setBaseUri(ConfigsGlobal.BASE_URI).
setBasePath(ConfigsGlobal.BASE_PATH).
addHeader("Authorization", "Bearer " + TokenGlobal.TOKEN).
setContentType(ContentType.JSON).
setAccept(ContentType.JSON).
addFilter(new RequestLoggingFilter()).
addFilter(new ResponseLoggingFilter()).
log(LogDetail.ALL).
build();
}
public static ResponseSpecification getResponseSpecBuilder() {
return new ResponseSpecBuilder().
expectContentType(ContentType.JSON).
log(LogDetail.ALL).
build();
}
public static RequestSpecification getRequestNotAuthSpecBuilder() {
return new RequestSpecBuilder().
setBaseUri(ConfigsGlobal.BASE_URI).
setBasePath(ConfigsGlobal.BASE_PATH).
setContentType(ContentType.JSON).
setAccept(ContentType.JSON).
addFilter(new RequestLoggingFilter()).
addFilter(new ResponseLoggingFilter()).
log(LogDetail.ALL).
build();
}
}
6. Xây dựng class API Keyword chính để sử dụng trong test cases
Class keyword vô cùng quan trọng vì nó sẽ đại diện cho cách thiết kế test cases của mình theo một chuẩn chung. Rút gọn code rất nhiều từ việc gọi các hàm từ class khác và khai báo đầy đủ các Logs và Reports.
Đối với class keyword chúng ta sẽ viết lại các hàm GET, POST, PUT, PATCH, DELETE và các hàm xử lý liên quan trong quá trình thực thi một test cases trực tiếp để sau này có thể bảo trì dễ dàng khi có sẵn các hàm đã được optimize dần.
ApiKeyword
package com.anhtester.keywords;
import com.anhtester.utils.LogUtils;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import java.io.File;
import java.util.Map;
import static io.restassured.RestAssured.given;
public class ApiKeyword {
public static Response get(String path) {
LogUtils.info("GET: " + path);
Response response =
given(SpecBuilder.getRequestSpecBuilder()).
when().
get(path).
then().
spec(SpecBuilder.getResponseSpecBuilder()).
extract().
response();
LogUtils.info("RESPONSE: \n" + response.prettyPrint());
return response;
}
public static Response get(String path, Map<String, String> headers) {
LogUtils.info("GET: " + path);
LogUtils.info("HEADERS: " + headers);
Response response =
given(SpecBuilder.getRequestSpecBuilder().headers(headers)).
when().
get(path).
then().
spec(SpecBuilder.getResponseSpecBuilder()).
extract().
response();
LogUtils.info("RESPONSE: \n" + response.prettyPrint());
return response;
}
public static Response get(String path, String authBearerToken) {
LogUtils.info("GET: " + path);
LogUtils.info("BEARER TOKEN: " + authBearerToken);
Response response =
given(SpecBuilder.getRequestSpecBuilder().header("Authorization", "Bearer " + authBearerToken)).
when().
get(path).
then().
spec(SpecBuilder.getResponseSpecBuilder()).
extract().
response();
LogUtils.info("RESPONSE: \n" + response.prettyPrint());
return response;
}
public static Response getNotAuth(String path) {
LogUtils.info("GET not authorization: " + path);
Response response =
given(SpecBuilder.getRequestNotAuthSpecBuilder()).
when().
get(path).
then().
spec(SpecBuilder.getResponseSpecBuilder()).
extract().
response();
LogUtils.info("RESPONSE: \n" + response.prettyPrint());
return response;
}
public static Response post(String path, Object payLoad) {
LogUtils.info("POST: " + path);
LogUtils.info("Body: " + payLoad);
Response response =
given(SpecBuilder.getRequestSpecBuilder()).
body(payLoad).
when().
post(path).
then().
spec(SpecBuilder.getResponseSpecBuilder()).
extract().response();
LogUtils.info("RESPONSE: \n" + response.prettyPrint());
return response;
}
public static Response postNotAuth(String path, Object payLoad) {
LogUtils.info("POST not authorization: " + path);
LogUtils.info("Body: " + payLoad);
Response response =
given(SpecBuilder.getRequestNotAuthSpecBuilder()).
body(payLoad).
when().
post(path).
then().
spec(SpecBuilder.getResponseSpecBuilder()).
extract().response();
LogUtils.info("RESPONSE: \n" + response.prettyPrint());
return response;
}
public static Response post(String path, String filePathBody) {
LogUtils.info("POST: " + path);
LogUtils.info("Body: " + filePathBody);
Response response =
given(SpecBuilder.getRequestSpecBuilder()).
body(new File(filePathBody)).
when().
post(path).
then().
spec(SpecBuilder.getResponseSpecBuilder()).
extract().response();
LogUtils.info("RESPONSE: \n" + response.prettyPrint());
return response;
}
public static Response put(String path, Object payLoad) {
LogUtils.info("PUT: " + path);
LogUtils.info("Body: " + payLoad);
Response response =
given(SpecBuilder.getRequestSpecBuilder()).
body(payLoad).
when().
put(path).
then().
extract().response();
LogUtils.info("RESPONSE: \n" + response.prettyPrint());
return response;
}
public static Response delete(String path, Object payLoad) {
LogUtils.info("DELETE: " + path);
LogUtils.info("Body: " + payLoad);
Response response =
given(SpecBuilder.getRequestSpecBuilder()).
body(payLoad).
when().
delete(path).
then().
extract().response();
LogUtils.info("RESPONSE: \n" + response.prettyPrint());
return response;
}
public static String getResponseKeyValue(Response response, String responseKey) {
JsonPath jsonPath = response.jsonPath();
String key_value = jsonPath.get(responseKey).toString();
LogUtils.info("Get body by key (" + responseKey + "): " + key_value);
return key_value;
}
public static String getResponseKeyValue(String responseBody, String responseKey) {
JsonPath jsonPath = new JsonPath(responseBody);
String key_value = jsonPath.get(responseKey).toString();
LogUtils.info("Get body by key (" + responseKey + "): " + key_value);
return key_value;
}
public static int getStatusCode(Response response) {
int status_code = response.getStatusCode();
LogUtils.info("Get Status Code: " + status_code);
return status_code;
}
public static String getStatusLine(Response response) {
String status_line = response.getStatusLine();
LogUtils.info("Get Status Line: " + status_line);
return status_line;
}
public static String getResponseHeader(Response response, String header_key) {
String response_header = response.getHeader(header_key);
LogUtils.info("Get Header by key (" + header_key + "): " + response_header);
return response_header;
}
public static String getResponseContentType(Response response) {
String content_type = response.getContentType();
LogUtils.info("Get Content Type: " + content_type);
return content_type;
}
public static String getResponseCookieName(Response response, String cookieName) {
String cookie_value = response.getCookie(cookieName);
LogUtils.info("Get Cookie by name (" + cookieName + "): " + cookie_value);
return cookie_value;
}
}
7. Xây dựng lại class TestListener cho đẹp mắt
TestListener
package com.anhtester.listeners;
import com.anhtester.globals.ConfigsGlobal;
import com.anhtester.helpers.PropertiesHelper;
import com.anhtester.utils.LogUtils;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
public class TestListener implements ITestListener {
@Override
public void onStart(ITestContext result) {
LogUtils.info("\n===============================================================\n==================== " + result.getSuite().getName().toUpperCase() + " STARTING ===================\n===============================================================");
//Read Properties - loadAllFiles()
PropertiesHelper.loadAllFiles();
//Select Database - lưu trữ vào biến toàn cục
//Connect tới bên thứ 3 cho thuê reports chẳng hạn
}
@Override
public void onFinish(ITestContext result) {
//Tổng kết lại tình hình chạy test
//In ra logs cho biết là đã kết thức và chạy được bao nhiêu cái pass/fail
//Gửi mail đến mail chung để nắm bắt tình hình - Lấy ra các biến toàn cục hoặc file logs, report
LogUtils.info("\n################################# FINISH ################################");
LogUtils.info("Đã gửi mail đến admin@anhtester.com");
LogUtils.info("Tổng số test cases: " + ConfigsGlobal.TCS_TOTAL);
LogUtils.info("Số test cases passed: " + ConfigsGlobal.PASSED_TOTAL);
LogUtils.info("Số test cases failed: " + ConfigsGlobal.FAILED_TOTAL);
}
@Override
public void onTestStart(ITestResult result) {
LogUtils.info("\n*****************************************************************");
LogUtils.info("Đang chạy test case " + result.getName());
//Mình sẽ bắt cái tên TCs để ghi logs và ghi vào report (Allure report)
ConfigsGlobal.TCS_TOTAL++;
}
@Override
public void onTestSuccess(ITestResult result) {
//Cộng 1 đơn vị vào 1 biến toàn cục để nắm bắt số lượng tcs pass
LogUtils.info("Test case " + result.getName() + " is passed.");
ConfigsGlobal.PASSED_TOTAL++;
}
@Override
public void onTestFailure(ITestResult result) {
//Cộng 1 đơn vị vào 1 biến toàn cục để nắm bắt số lượng tcs fail
LogUtils.error("Test case " + result.getName() + " is failed.");
LogUtils.error(result.getThrowable());
ConfigsGlobal.FAILED_TOTAL++;
}
@Override
public void onTestSkipped(ITestResult result) {
LogUtils.warn("Test case " + result.getName() + " is skipped.");
}
}
8. Thiết lập BaseTest gọn ràng hơn
BaseTest
package com.anhtester.common;
import com.anhtester.globals.EndPointGlobal;
import com.anhtester.globals.TokenGlobal;
import com.anhtester.helpers.PropertiesHelper;
import com.anhtester.keywords.ApiKeyword;
import com.anhtester.model.LoginPOJO;
import com.anhtester.model.data.LoginPOJO_Builder;
import com.anhtester.utils.LogUtils;
import com.google.gson.Gson;
import io.restassured.response.Response;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import static io.restassured.RestAssured.given;
public class BaseTest {
@BeforeTest
public void loginUser() {
LogUtils.info("********LOGIN USER********");
//LoginPOJO loginPOJO = new LoginPOJO(ConfigsGlobal.USERNAME, ConfigsGlobal.PASSWORD);
LoginPOJO loginPOJO = LoginPOJO_Builder.getDataLogin();
Gson gson = new Gson();
// RequestSpecification request = given();
// request.baseUri(ConfigsGlobal.BASE_URI)
// .accept("application/json")
// .contentType("application/json")
// .body(gson.toJson(loginPOJO));
//
// Response response = request.when().post("/login");
Response response = ApiKeyword.postNotAuth(EndPointGlobal.EP_LOGIN, gson.toJson(loginPOJO));
response.then().statusCode(200);
TokenGlobal.TOKEN = ApiKeyword.getResponseKeyValue(response, "token");
LogUtils.info("Token Global: " + TokenGlobal.TOKEN);
}
}
✳️ Viết test cases với các hàm xây dựng sẵn
package com.anhtester.Bai17_Keyword;
import com.anhtester.common.BaseTest;
import com.anhtester.globals.EndPointGlobal;
import com.anhtester.keywords.ApiKeyword;
import com.anhtester.listeners.TestListener;
import com.anhtester.utils.LogUtils;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import org.testng.Assert;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import static io.restassured.RestAssured.given;
@Listeners(TestListener.class)
public class CategoryTest_Keyword extends BaseTest {
int CATEGORY_ID;
String CATEGORY_NAME;
@Test(priority = 1)
public void testAddNewCategory() {
String dataFile = "src/test/resources/testdata/CreateCategory.json";
// RequestSpecification request = given();
// request.baseUri("https://api.anhtester.com/api")
// .accept(ContentType.JSON)
// .contentType(ContentType.JSON)
// .header("Authorization", "Bearer " + TokenGlobal.TOKEN)
// .body(new File(dataFile));
Response response = ApiKeyword.post(EndPointGlobal.EP_CATEGORY, dataFile);
response.then().statusCode(200);
CATEGORY_ID = Integer.parseInt(ApiKeyword.getResponseKeyValue(response, "response.id"));
CATEGORY_NAME = ApiKeyword.getResponseKeyValue(response, "response.name");
LogUtils.info("CATEGORY_ID: " + CATEGORY_ID);
LogUtils.info("CATEGORY_NAME: " + CATEGORY_NAME);
}
@Test(priority = 2)
public void getCategoryById() {
// RequestSpecification request = given();
// request.baseUri("https://api.anhtester.com/api")
// .accept(ContentType.JSON)
// .contentType(ContentType.JSON)
// .header("Authorization", "Bearer " + TokenGlobal.TOKEN);
LogUtils.info("CATEGORY_ID: " + CATEGORY_ID);
Response response = ApiKeyword.get("/category/" + CATEGORY_ID);
response.then().statusCode(200);
Assert.assertEquals(ApiKeyword.getResponseKeyValue(response, "response.name"), CATEGORY_NAME, "The Category Name not match.");
}
}