Ở bài này, mình sẽ hướng dẫn xử lý việc duplicate code một cách đơn giản và sẽ còn sử dụng cách này để làm những bài tiếp theo.
Ta thấy 2 cái test case ở bài trước, đều có chung nhau 1 đoạn như sau:
driver = new FirefoxDriver(); driver.get(URL_login); driver.findElement(By.id(user_login)).sendKeys(""); driver.findElement(By.id(user_pass)).sendKeys(""); driver.findElement(By.id(submitBtn)).click();
Chỉ khác nhau cái giá trị username và password truyền vào thôi. Thế ta sẽ viết 1 cái function dùng chung luôn nhỉ. Function này sẽ linh hoạt cái giá trị username và password là xong.
Function dùng chung đây:
public void login(String userName, String password) { WebDriver driver = new FirefoxDriver(); driver.get(URL_login); driver.findElement(By.id(user_login)).sendKeys(userName); driver.findElement(By.id(user_pass)).sendKeys(password); driver.findElement(By.id(submitBtn)).click(); }
Do function này không phải là Test case nên ta không cần đặt annotation @Test vào. Sau đó ta bỏ những dòng code ở các testcase ra và thay bằng function login.
Tuy nhiên, sau khi viết thì Eclipse báo lỗi ở chỗ các vị trí driver, lý do là cái object driver nó đang được khai báo và khởi tạo ở function login, nó không có ảnh hưởng gì đến các method test. Để fix, ta phải biến cái driver ấy thành Instance variable, bằng cách khai báo nó ngoài các method.
Code sau khi sửa sẽ thành thế này:
WebDriver driver; public void login(String userName, String password) { driver = new FirefoxDriver(); driver.get(URL_login); driver.findElement(By.id(user_login)).sendKeys(userName); driver.findElement(By.id(user_pass)).sendKeys(password); driver.findElement(By.id(submitBtn)).click(); } @Test public void loginByAdmin() { login("giang", "123456789"); Assert.assertEquals(driver.getCurrentUrl(), URL_dashBoard); driver.quit(); } @Test public void loginWithBlankField() { login("", ""); Assert.assertEquals(driver.getCurrentUrl(), URL_login); driver.quit(); }
Ta chợt thấy hình như ta càng ngày càng làm các method Test ngắn gọn hơn thì phải. Yeah, chúng ta đang trên đường build Test Automation Framework, việc chúng ta phải làm là: Làm cho test càng đơn giản càng tốt, phần xử lý phức tạp sẽ để Framework xử lý.
Nhìn vào đoạn trên ta vẫn thấy còn có 2 chỗ nữa vẫn không tốt:
- driver.quit() đang bị lặp lại ở các test case.
- Function login() đang có nhiều hơn 1 chức năng: Khởi tạo Object, vào trang login, thực hiện login
1. Để xử lý phần lặp lại driver.quit() ta sử dụng thêm 1 cái annotation nữa của TestNG là @AfterMethod. Cái method nào có sử dụng annotation này sẽ run sau 1 method test. Và như thế ta sẽ không cần viết driver.quit() ở mỗi test case nữa
@AfterMethod public void tearDown() { driver.quit(); }
2. Ta cần phải viết lại để cái function login() chỉ có 1 chức năng login duy nhất thôi. Có thể đến đây bạn sẽ phân vân là thế thì driver.get(URL_login) có được đặt vào function login không hay mình sẽ phải viết ở chỗ khác?
Ta suy nghĩ 1 chút, có phải là hầu hết các test case của ta đều sẽ làm việc với trang login đầu tiên đúng không? Thế thì việc vào trang login là điều mà test case nào cũng sẽ có. Do đó ta nên đặt nó vào 1 chỗ mà sẽ run trước tất cả các method test. Ok, sử dụng tiếp 1 annotation nữa của TestNG: @BeforeMethod.
@BeforeMethod public void setUp(){ WebDriver driver = new FirefoxDriver(); driver.get(URL_login); }
Code hoàn chỉnh sẽ như sau:
import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class LoginTest { String URL_login = "http://localhost/wp/wp-login.php"; String URL_dashBoard = "http://localhost/wp/wp-admin/"; String user_login = "user_login"; String user_pass = "user_pass"; String submitBtn = "wp-submit"; WebDriver driver; public void login(String userName, String password) { driver.findElement(By.id(user_login)).sendKeys(userName); driver.findElement(By.id(user_pass)).sendKeys(password); driver.findElement(By.id(submitBtn)).click(); } @BeforeMethod public void setUp(){ driver = new FirefoxDriver(); driver.get(URL_login); } @Test public void loginByAdmin() { login("giang", "123456789"); Assert.assertEquals(driver.getCurrentUrl(), URL_dashBoard); } @Test public void loginWithBlankField() { login("", ""); Assert.assertEquals(driver.getCurrentUrl(), URL_login); } @AfterMethod public void tearDown() { driver.quit(); } }
Cái method Test ngắn lại nữa rồi. Nhìn thích phết :D.
Bạn đang vui mừng vì cái Script của bạn đang ngày càng đẹp lên, và bạn lại nghĩ rằng code automation vẫn dễ, ngày mai sẽ viết thêm 1 đống test nữa. Nhưng mà bạn ơi, lại có vấn đề tiếp:
- Ngày mai bạn viết thêm 1 Class khác để test chức năng “Tạo bài viết mới”. Bạn chợt nhận ra rằng, hình như mai mình sẽ phải copy mấy cái BeforeMethod, AfterMethod từ Class LoginTest này sang. Ớ ớ ớ, vừa mới học để xử lý duplicate code xong, bây giờ lại chuẩn bị duplicate code ở chỗ mới. =))))))
- Trang login này có ít element và ít test case nên cái class của bạn nó còn ngắn. Thế sang 1 cái chức năng ở 1 màn hình khác có rất nhiều element và rất nhiều test case thì cái Class test của bạn sẽ rất dài và rất loạn.
- Khi test manual thì mỗi lần test đâu có cần đóng browser rồi mở lại đâu nhỉ?
- Chức năng khác đều yêu cầu login thành công trước, thế mình phải copy nguyên cái đoạn code của login đi khắp các Class test ah. Xử lý thế nào đây?
Nhiều vấn đề quá nhỉ…hiu hiu…Hãy tiếp tục đọc các bài tiếp theo nhé. 😀
[…] ← Previous Next → […]
[…] ← Previous […]
[…] khi nhìn lại vào test case, ta lại nhận thấy vài vấn đề mà bài 9 đã nhắc đến nhưng chưa xử lý […]
Biết viết của Giang đúng là những gì mình đang cần về cả cấu trúc, tư duy
Cảm ơn nhiều nhiều
thanks bạn. 😀
Thực sự cảm ơn anh rất nhiều. Bài viết cực kì hữu ích với newbie vẫn đang chập chững với các khái niệm của Java như mình. Tâm huyết thực sự chứ không chỉ là đọc và dịch như các trang khác. Many thanks.
Cảm ơn bạn, bạn chỉ nên đọc blog để tham khảo cái idea thôi, chứ hồi này mình code kém lắm, viết còn sai nhiều.
Form Login của hệ thống em đang test dùng google captcha bằng hình ảnh, mình có cách nào pass qua được case này không anh?
Anh Sang Bùi có khá nhiều cách để xử lý vấn đề này rồi em nhé.
https://sangbui.com/co-the-thuc-hien-auto-hoac-performance-khi-web-co-captcha/
Bài viết của anh hay quá, em cảm ơn anh nhiều!
Không có gì bạn 😀
Em chạy thấy báo lỗi FAILED CONFIGURATION: @AfterMethod tearDown ạ
mà nó chỉ dừng lại sau khi chạy hàm loginWithBlankField? Anh cho em hỏi lỗi này đang bị như thế nào vậy ạ?
Em ping skype nguyen_duy_giang nhé em. Anh không biết em có làm sai gì ko. Thanks!
Theo như anh tạm hiểu: @AfterMethod error –> ko quit browser –> chương trình dừng lại ở loginWithBlankField
Thật sự rất thích các anh phân tích, theo luồng logic rồi giải quyết vấn đề
Cảm ơn bạn, bạn chỉ nên đọc blog để tham khảo thôi, chứ hồi này mình code kém lắm, viết còn sai nhiều.