NỘI DUNG BÀI HỌC

Viết các hàm xử lý dạng class Keyword để rút gọn code và config data chung.

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 RequestResponse 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 LogsReports.

Đố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.");

    }
}

Teacher

Teacher

Anh Tester

Software Quality Engineer

Đường dẫu khó chân vẫn cần bước đi
Đời dẫu khổ tâm vẫn cần nghĩ thấu

Cộng đồng Automation Testing Việt Nam:

🌱 Telegram Automation Testing:   Cộng đồng Automation Testing
🌱 
Facebook Group Automation: Cộng đồng Automation Testing Việt Nam
🌱 
Facebook Fanpage: Cộng đồng Automation Testing Việt Nam - Selenium
🌱 Telegram
Manual Testing:   Cộng đồng Manual Testing
🌱 
Facebook Group Manual: Cộng đồng Manual Testing Việt Nam

Chia sẻ khóa học lên trang

Bạn có thể đăng khóa học của chính bạn lên trang Anh Tester để kiếm tiền

Danh sách bài học