npmtam / Automation-Testing-Articles

Nơi lưu trữ các bài viết chia sẻ về các tips cũng như tutorials về automation testing
2 stars 1 forks source link

Sử dụng Google SpreadSheet (Google Sheet) để thực hiện data-driven testing trong Selenium Java #1

Open npmtam opened 3 years ago

npmtam commented 3 years ago

Hiện nay, Google Spreadsheet có vẻ như đã quá quen thuộc, nhất là với những người làm kiểm thử như chúng ta.

Nó là một công cụ hữu ích và tiện lợi. Đặc biệt có thể chia sẻ online các trang tính với nhau. Nhiều công ty vẫn sử dụng nó để lưu trữ các test cases, test reports hay những thông tin cần thiết.

Ngoài ra, nó có vẻ như còn là một công cụ hỗ trợ tốt cho chúng ta lưu trữ các thông tin cần thiết để sử dụng trong data driven framework. Nó có thể là một công cụ tốt để thay thế cho các external files khác như excel, csv, SQL server, ....

Ưu điểm rất lớn của nó là chúng ta có thể gửi cho người khác xem chỉ với một đường link. Sẽ tiện hơn so với các external files khác rất nhiều.

Thay vì sử dụng Apache POI để thao tác với excel, sao ta không sử dụng luôn Google Spreadsheet nhỉ? 😄

Hãy cùng tìm hiểu một vài câu lệnh cơ bản để thao tác với Google Spreadsheet API nhé.

Bài toán ví dụ: Ở đây mình sẽ demo về một trường hợp của data-driven testing với external file. Đăng ký tài khoản tại site demo http://demo.guru99.com/v4/

Bắt đầu nào. Ở đây mình sẽ demo với class dạng step by step. Các bạn tự apply vào design pattern riêng nhé

I. Cấu hình các thông tin cần thiết

1. Enable the Google Sheets API

Việc đầu tiên là phải bật chức năng này trong account của bạn lên và download file credentials.json này về

1

3

4

5

Lúc này chúng ta đã có các thông tin chứng thực cần thiết để sử dụng được các quyền với các trang tính trong phạm vi quyền hạn của account chúng ta

2. Import các thư viện của Google API vào dự án

2.1: Đối với Maven project

<!-- TestNG -->
<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>6.8.8</version>
</dependency>
<!-- Selenium Java -->
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>3.141.59</version>
</dependency>

<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-support</artifactId>
    <version>3.141.59</version>
</dependency>
<dependency>
    <groupId>io.github.bonigarcia</groupId>
    <artifactId>webdrivermanager</artifactId>
    <version>3.6.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.api-client/google-api-client -->
<dependency>
    <groupId>com.google.api-client</groupId>
    <artifactId>google-api-client</artifactId>
    <version>1.22.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.oauth-client/google-oauth-client-jetty -->
<dependency>
    <groupId>com.google.oauth-client</groupId>
    <artifactId>google-oauth-client-jetty</artifactId><version>1.22.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.apis/google-api-services-sheets -->
<dependency>
    <groupId>com.google.apis</groupId>
    <artifactId>google-api-services-sheets</artifactId>
    <version>v4-rev456-1.22.0</version>
</dependency>

2.2: Đối với Gradle: Thêm các dependencies vào file build.gradle

apply plugin: 'java'
apply plugin: 'application'

mainClassName = 'SheetsQuickstart'
sourceCompatibility = 1.8
targetCompatibility = 1.8
version = '1.0'

repositories {
    mavenCentral()
}

dependencies {
    compile 'com.google.api-client:google-api-client:1.30.4'
    compile 'com.google.oauth-client:google-oauth-client-jetty:1.30.4'
    compile 'com.google.apis:google-api-services-sheets:v4-rev581-1.25.0'
}
npmtam commented 3 years ago

II. Thao tác với Google Sheets

Ở đây mình sẽ tạo một class "SpreadSheetIntegration.java" để đảm nhiệm việc thao tác với Google SpreadSheet API

1. Đầu tiên là khai báo các biến cần thiết và tạo constructor: Vì ở đây mình chỉ sử dụng 2 cột để lưu trữ userID và password nên mình sẽ khai báo range = A:B

    public String ROOT_FORLDER = System.getProperty("user.dir");
    public final String APPLICATION_NAME = "Test Spreadsheet";
    public final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    public final String TOKENS_DIRECTORY_PATH = "tokens";
    public final String CREDENTIAL_FILE_PATH = "/credentials.json";

    public final List<String> SCOPES = Collections.singletonList(SheetsScopes.SPREADSHEETS);
    public NetHttpTransport HTTP_TRANSPORT = null; //Khai báo HTTP Transport
    public Sheets service; //Khai báo Sheet service
    public String valueInputOption = "USER_ENTERED"; //Khai báo option của input
    public ValueRange response; //Khai báo response
    public String spreadSheetID; //Lưu trữ spread sheet ID của sheet được tạo ra
    public String range = "A:B"; //Khai báo range muốn xử lý trong google sheet

    //Tạo constructure để khởi tạo service và HTTP_TRANSPORT
    public SpreadSheetIntegration() throws IOException, GeneralSecurityException {
        HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
        service = new Sheets.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredential(HTTP_TRANSPORT))
                .setApplicationName(APPLICATION_NAME)
                .build();
    }

2. Tạo hàm getCredentials để lấy quyền xác thực với tài khoản

/**
     * Function to create an authorized credential object
     * @param HTTP_TRANSPORT The network HTTP Transport.
     * @return An authorized Credential object
     * @throws IOException If the credentials.json file can not be found
     */
    public Credential getCredential(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
        //Load client secrets
        InputStream in = SpreadSheetIntegration.class.getResourceAsStream(CREDENTIAL_FILE_PATH);
        if (in == null) {
            throw new FileNotFoundException("Resource not found: " + CREDENTIAL_FILE_PATH);
        }
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

        //Build flow and trigger user authorization request
        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
                .setAccessType("offline")
                .build();
        LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
        return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
    }

3. Tiếp theo là hàm tạo một sheet mới Bạn có thể set tiêu đề cho sheet mới với lệnh setTitle(title);

  public void createANewSheet() throws IOException {
        Spreadsheet spreadsheet = new Spreadsheet()
                .setProperties(new SpreadsheetProperties()
                        .setTitle("Sheet Test"));
        spreadsheet = service.spreadsheets().create(spreadsheet)
                .setFields("spreadsheetId")
                .execute();
        spreadSheetID = spreadsheet.getSpreadsheetId(); //Gán giá trị spreadSheetID cho sheet mới tạo
        //In ra link Google Sheet vừa tạo
        System.out.println("http://docs.google.com/spreadsheets/d/" + spreadSheetID);
    }

4. Hàm ghi thêm giá trị vào sheet vừa tạo

    public void appendDataToSpreadSheet(Object username, Object password) {
        List<List<Object>> values = Arrays.asList(
                Arrays.asList(username, password)
        );
        ValueRange body = new ValueRange().setValues(values);
        try {
            AppendValuesResponse result = service.spreadsheets().values().append(spreadSheetID, range, body).setValueInputOption(valueInputOption).execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

5. Hàm đọc giá trị từ sheet vừa tạo

    public List<String> readDataFromSpreadSheet() throws IOException {
       List<String> dataSet = new ArrayList<String>();
       response = service.spreadsheets().values().get(spreadSheetID, range).execute();
       List<List<Object>> values = response.getValues();

       if (values == null || values.isEmpty()) {
           System.out.println("No data found");
       } else {
           for (List row : values) {
               dataSet.add(row.get(0) + " " + row.get(1));
           }
       }
       return dataSet;
   }

Tạm thời trong bài demo này mình chỉ cần sử dụng đến những hàm này. Class mình sẽ để link ở đây

npmtam commented 3 years ago

III. Apply Google Sheet cho Automation

Tiếp theo, hãy cùng tạo một class test với TestNG để thực hiện automation.

1. Tạo class test

Tạo một class test sử dụng Selenium và TestNG để thực hiện việc automation. Ở đây mình sẽ tạo class SpreadSheetTest.java trong test/java

Cùng tham khảo class test phía dưới nhé:

public class SpreadSheetTest {
    private WebDriver driver;
    private SpreadSheetIntegration spreadsheet;
    private String email, userID, password;

    @BeforeClass
    public void beforeClass() throws IOException, GeneralSecurityException {
        WebDriverManager.chromedriver().setup(); //tự động nhận diện và tải về Chrome driver
        driver = new ChromeDriver();

        driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); //Set Global implicit wait time
        driver.manage().window().maximize();

        //Khởi tạo lớp SpreadsheetIntegration
        spreadsheet = new SpreadSheetIntegration();

        //Đầu tiên tạo 1 google sheet mới để ghi và đọc thông tin
        spreadsheet.createANewSheet();
    }

    @Test (invocationCount = 5)
    public void step1_RegisterANewAccount() throws IOException {
        //Truy cập site demo
        driver.get("http://demo.guru99.com/v4/");

        //Click vào link để đăng ký account
        driver.findElement(By.xpath("//a[text()='here']")).click();

        //Điền email để đăng ký account
        email = "tam" + randomNumber() + "@mail.com";
        driver.findElement(By.name("emailid")).sendKeys(email);

        //Nhấn submit để đăng ký account
        driver.findElement(By.name("btnLogin")).click();

        //Lấy userID đã được generate
        userID = driver.findElement(By.xpath("//td[text()='User ID :']/following-sibling::td")).getText();

        //Lấy password đã được generate
        password = driver.findElement(By.xpath("//td[text()='Password :']/following-sibling::td")).getText();

        //Ghi tiếp giá trị userID và password và sheet vừa tạo
        spreadsheet.appendDataToSpreadSheet(userID, password);
    }

    @Test
    public void step2_loginWithDataSet() throws IOException {
        List<String> dataSet = spreadsheet.readDataFromSpreadSheet();
        for(int i=0; i<dataSet.size(); i++){
            driver.get("http://demo.guru99.com/v4/");
            String[] userInfo = dataSet.get(i).split(" ");
            String userId = userInfo[0];
            String password = userInfo[1];
            driver.findElement(By.name("uid")).sendKeys(userId);
            driver.findElement(By.name("password")).sendKeys(password);
            driver.findElement(By.name("btnLogin")).click();
            String welcomeMsg = driver.findElement(By.xpath("//tr[@class='heading3']/td")).getText();
            Assert.assertTrue(welcomeMsg.contains(userId));
        }
    }

    @AfterTest
    public void afterTest(){
        driver.quit();
    }

    /**
     * Hàm tạo số random
     * @return số random
     */
    public int randomNumber(){
        Random random = new Random();
        int randomNumber = random.nextInt(999);
        return randomNumber;
    }
}

Giải thích về class trên một chút: Ở đây mình dùng class dạng step by step nên sẽ bỏ trực tiếp các hàm cần thiết vào trong class này luôn

Tiếp theo thì chạy thử thôi nào.

Kết quả sau khi chạy thử:

Trong console sẽ generate ra một link Google Sheet mới, trong này sẽ chứa những userId và password mà chúng ta đã ghi vào trước đó. giờ chỉ việc chia sẻ bằng cách phân quyền và gửi link cho người khác về bộ data của mình thôi:

Kết quả của mình: https://docs.google.com/spreadsheets/d/1UKNJHqxwIsVdEy8Lk6R_-eKQLB9Bz-cm_LNpD1f_dwg/edit?usp=sharing

npmtam commented 3 years ago

Lưu ý:

Vì ở đây mình sử dụng quyền đọc ghi dữ liệu (SCOPES = Collections.singletonList(SheetsScopes.SPREADSHEETS)) nên ta phải xác minh và cấp quyền cho file credentials.json bằng account. (Những lần sau thì tokens sẽ được lưu lại và chúng ta không cần phải thực hiện bước này nữa)

Nếu chỉ sử dụng quyền Read Only (SCOPES = Collections.singletonList(SheetsScopes.SPREADSHEETS_READONLY)) thì sẽ không cần phải cấp quyền từ account, không qua bước này.

6

7

8

Sau khi đã cấp quyền thành công, script sẽ chạy bình thường. Tokens sẽ được tự động lưu dưới thư mục dự án trong folder "tokens" và chúng ta sẽ không cần phải xác thực quyền ở những lần chạy tiếp theo.

Ở phần trên mình đã in ra spreadSheetID, nên sau khi chạy xong chỉ việc vào console lấy link ra và chúng ta đã có thể gửi cho người khác bộ data test mà chúng ta sử dụng. Cũng khá là tiện phải không nào.

Như vậy là chúng ta đã có thể thao tác với Google SpreadSheet API trong Selenium Java. Việc áp dụng vào design pattern cũng tương tự nhé.

Hy vọng bài viết này giúp ích cho mọi người.