1. 思維導(dǎo)圖編寫 Web 自動化測試用例
2. 創(chuàng)建測試項目
- 創(chuàng)建 Maven 項目
- 在 test 包下編寫相關(guān)測試代碼
- 導(dǎo)入自動化測試需要的相關(guān)依賴
在 pom.xml 中引入自動化測試相關(guān)依賴:
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.0.0</version>
</dependency>
<!-- 保存屏幕截圖文件需要用到的包-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<!-- Junit 中 參數(shù)化測試 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<!-- junit 中 測試套件 -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<version>1.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
3. 根據(jù)思維導(dǎo)圖設(shè)計用戶管理系統(tǒng)自動化測試用例
3.1 準備工具類
在 common 包下創(chuàng)建 AutoTestUtils 類,該類需要提供以下功能:
- 創(chuàng)建驅(qū)動對象,提供給頁面使用。
- 創(chuàng)建隱式等待,作用于驅(qū)動對象的整個生命周期。
- 提供屏幕截圖方法,以及保存截圖的格式。
/**
* @Description: 創(chuàng)建驅(qū)動對象;提供屏幕截圖方法
* @Date 2023/4/15 9:59
* @Author:
*/
public class AutoTestUtils {
public static EdgeDriver driver;
/**
* @param : 創(chuàng)建驅(qū)動對象
* @return EdgeDriver
* @description TODO
*/
public static EdgeDriver createDriver() {
EdgeOptions options = new EdgeOptions();
options.addArguments("-remote-allow-origins=*");
// 驅(qū)動對象沒有創(chuàng)建
if(driver == null) {
driver = new EdgeDriver(options);
// 創(chuàng)建隱式等待
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
}
// 驅(qū)動對象已經(jīng)創(chuàng)建好了
return driver;
}
/**
* @param str: 類名
* @return void
* @description 獲取屏幕截圖,把所有的用例執(zhí)行的結(jié)果都保存下來
*/
public void getScreenShot(String str) throws IOException {
List<String> list = getTime();
// ./src/test/java/com/usermanagerWebAutoTest/日期/類名_日期_時間.png
String filename = "./src/test/java/com/usermanagerWebAutoTest/" + list.get(0) +
"/" + str + "_" + list.get(1) + ".png";
// 進行屏幕截圖
File srcFile = driver.getScreenshotAs(OutputType.FILE);
// 將屏幕截圖生成的圖片放到指定路徑下
FileUtils.copyFile(srcFile,new File(filename));
}
public List<String> getTime() {
// 文件格式 2023-04-15/2023-04-15_12:36:00
SimpleDateFormat sim1 = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sim2 = new SimpleDateFormat("yyyyMMdd-HHmmssSS");
// 以天的維度按文件夾進行保存
String dirname = sim1.format(System.currentTimeMillis());
String filename = sim2.format(System.currentTimeMillis());
List<String> list = new ArrayList<>();
list.add(dirname);
list.add(filename);
return list;
}
}
在 Tests 包下創(chuàng)建 DriverQuitTest 類,該類的主要作用是用來釋放驅(qū)動
/**
* @Description: 釋放驅(qū)動
* @Date 2023/4/15 9:59
* @Author:
*/
public class DriverQuitTest extends AutoTestUtils {
public static EdgeDriver driver = createDriver();
@Test
void driverQuit() {
driver.quit();
}
}
在 Tests 包下創(chuàng)建 runSuite 類,該類的就是測試套件
/**
* @Description: 測試套件
* @Date 2023/4/15 10:00
* @Author:
*/
@Suite
@SelectClasses({UserNoLoginTest.class,UserLoginTest.class,UserListTest.class,AddUserTest.class,UpdateUserTest.class,DriverQuitTest.class})
public class runSuite {
}
3.2 測試登錄頁面
創(chuàng)建 UserLoginTest 類,該類的測試用例有 6 個。
- 頁面是否可以正常打開
- 不輸入用戶名,輸入密碼,點擊登錄
- 輸入用戶名,不輸入密碼,點擊登錄
- 用戶名和密碼都不輸入,點擊登錄
- 輸入錯誤的用戶名和密碼,點擊登錄
- 輸入正確的用戶名和密碼,點擊登錄
/**
* @Description: 測試登錄頁面
* @Date 2023/4/15 10:00
* @Author:
*/
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UserLoginTest extends AutoTestUtils {
// 1. 訪問瀏覽器對象 2. 訪問登錄頁面的 URL
public static EdgeDriver driver = createDriver();
@BeforeAll
static void baseControl() {
driver.get("http://47.108.57.239:8080/login.html");
}
/**
* @param :
* @return void
* @description 檢查頁面是否可以正常打開
*/
@Test
@Order(1)
void loginPageLoadRight() throws IOException {
driver.findElement(By.cssSelector("#body > div > h3"));
driver.findElement(By.cssSelector("#loginname"));
driver.findElement(By.cssSelector("#submit"));
getScreenShot(getClass().getName());
}
/**
* @param password:
* @return void
* @description 不輸入用戶名,輸入密碼,點擊登錄
*/
@ParameterizedTest
@CsvSource({"111"})
@Order(2)
void loginFailUsernameNull(String password) throws InterruptedException, IOException {
driver.findElement(By.cssSelector("#loginname")).clear(); // 先清空一下
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#submit")).click();
// 登錄失敗結(jié)果檢測
Thread.sleep(1000);
// 切換到彈窗進行處理
Alert alert = driver.switchTo().alert();
// 點擊確認
alert.accept();
getScreenShot(getClass().getName());
}
/**
* @param username:
* @return void
* @description 輸入用戶名,不輸入密碼,點擊登錄
*/
@ParameterizedTest
@CsvSource({"111"})
@Order(3)
void loginFailPasswordNull(String username) throws InterruptedException, IOException {
driver.findElement(By.cssSelector("#loginname")).clear(); // 先清空一下
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#loginname")).sendKeys(username);
driver.findElement(By.cssSelector("#submit")).click();
// 登錄失敗結(jié)果檢測
Thread.sleep(1000);
// 切換到彈窗進行處理
Alert alert = driver.switchTo().alert();
// 點擊確認
alert.accept();
getScreenShot(getClass().getName());
}
/**
* @return void
* @description 用戶名和密碼都不輸入,點擊登錄
*/
@Test
@Order(4)
void loginFailUsernameAndPasswordNull() throws InterruptedException, IOException {
driver.findElement(By.cssSelector("#loginname")).clear(); // 先清空一下
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#submit")).click();
// 登錄失敗結(jié)果檢測
Thread.sleep(1000);
// 切換到彈窗進行處理
Alert alert = driver.switchTo().alert();
// 點擊確認
alert.accept();
getScreenShot(getClass().getName());
}
/**
* @return void
* @description 輸入錯誤的用戶名和密碼,點擊登錄
*/
@ParameterizedTest
@CsvSource({"1111,1111"})
@Order(5)
void loginFail(String username,String password) throws InterruptedException, IOException {
driver.findElement(By.cssSelector("#loginname")).clear(); // 先清空一下
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#loginname")).sendKeys(username);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#submit")).click();
// 登錄失敗結(jié)果檢測
Thread.sleep(1000);
// 切換到彈窗進行處理
Alert alert = driver.switchTo().alert();
// 點擊確認
alert.accept();
getScreenShot(getClass().getName());
}
/**
* @return void
* @description 輸入正確的用戶名和密碼,點擊登錄
*/
@ParameterizedTest
@CsvSource({"admin,admin"})
@Order(6)
void loginSucced(String username,String password) throws InterruptedException, IOException {
driver.findElement(By.cssSelector("#loginname")).clear(); // 先清空一下
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#loginname")).sendKeys(username);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#submit")).click();
// 登錄成功檢測,如果跳轉(zhuǎn)到用戶列表頁,才算是成功的
driver.findElement(By.cssSelector("#body > div > h3"));
Thread.sleep(2000);
getScreenShot(getClass().getName());
// 這里頁面跳轉(zhuǎn)了,重新返回到登錄頁面
driver.navigate().back();
}
}
3.3 測試用戶列表頁
創(chuàng)建 UserListTest 類,該類的測試用例有 4 個(默認登錄狀態(tài)下)。
- 頁面內(nèi)容顯示是否正常
- 是否能跳轉(zhuǎn)到添加用戶頁
- 是否能跳轉(zhuǎn)到修改用戶頁
- 查詢用戶功能是否正常
/**
* @Description: 測試用戶列表頁
* @Date 2023/4/15 10:00
* @Author:
*/
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UserListTest extends AutoTestUtils {
public static EdgeDriver driver = createDriver();
@BeforeAll
static void baseControl() {
driver.get("http://47.108.57.239:8080/list.html");
}
/**
* @return void
* @description 檢查頁面內(nèi)容顯示是否正常
*/
@Test
@Order(1)
void ListPageLoadRight() throws InterruptedException, IOException {
driver.findElement(By.cssSelector("#submit1"));
driver.findElement(By.cssSelector("#body > div > table > tbody:nth-child(1) > tr > th:nth-child(1)"));
driver.findElement(By.cssSelector("#all > li:nth-child(1) > a"));
driver.findElement(By.cssSelector("#body > div > div:nth-child(3) > a:nth-child(1)"));
driver.findElement(By.cssSelector("#delete"));
Thread.sleep(1000);
getScreenShot(getClass().getName());
}
/**
* @return void
* @description: 檢測添加用戶按鈕鏈接跳轉(zhuǎn)正常
*/
@Test
@Order(2)
void LinkJumpAdd() throws IOException, InterruptedException {
driver.findElement(By.cssSelector("#body > div > div:nth-child(3) > a:nth-child(1)")).click();
Thread.sleep(1000);
getScreenShot(getClass().getName());
driver.navigate().back();
}
/**
* @return void
* @description: 檢測修改用戶按鈕鏈接跳轉(zhuǎn)正常
*/
@Test
@Order(3)
void LinkJumpUpdate() throws IOException, InterruptedException {
driver.findElement(By.cssSelector("#info > tr:nth-child(1) > th:nth-child(10) > a:nth-child(1)")).click();
Thread.sleep(1000);
getScreenShot(getClass().getName());
driver.navigate().back();
}
/**
* @return void
* @description: 檢測查詢用戶功能是否正常
*/
@ParameterizedTest
@CsvSource({"超級管理員"})
@Order(4)
void SelectUser(String name) throws IOException, InterruptedException {
driver.findElement(By.cssSelector("#ipt_name")).sendKeys(name);
driver.findElement(By.cssSelector("#submit1")).click();
driver.findElement(By.cssSelector("#info > tr > th:nth-child(3)"));
Thread.sleep(1000);
getScreenShot(getClass().getName());
}
}
3.4 測試添加用戶頁
創(chuàng)建 AddUserTest 類,該類的測試用例有 5 個(默認登錄狀態(tài)下)。
- 頁面內(nèi)容是否顯示正常
- 管理員權(quán)限為超管,填寫用戶信息時,如果用戶名重復(fù),不能提交。
- 管理員權(quán)限為超管,填寫用戶信息時,如果用戶名不重復(fù),可以提交。
- 管理員權(quán)限為普通用戶,可以正常填寫信息,但不可以提交。
- 返回鏈接跳轉(zhuǎn)正常。
/**
* @Description: 測試添加用戶頁
* @Date 2023/4/15 10:00
* @Author:
*/
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class AddUserTest extends AutoTestUtils {
public static EdgeDriver driver = createDriver();
@BeforeAll
static void baseControl() {
driver.get("http://47.108.57.239:8080/add.html");
}
/**
* @return void
* @description 檢查頁面內(nèi)容顯示是否正常
*/
@Test
@Order(1)
void AddPageLoadRight() throws InterruptedException, IOException {
driver.findElement(By.cssSelector("#username"));
driver.findElement(By.cssSelector("#password"));
driver.findElement(By.cssSelector("#btn_sub"));
driver.findElement(By.cssSelector("#btn_back"));
Thread.sleep(1000);
getScreenShot(getClass().getName());
}
/**
* @return void
* @description :管理員權(quán)限為超管,填寫用戶信息時,如果用戶名重復(fù),不能提交。
*/
@ParameterizedTest
@CsvSource({"111,111,111,111,20,111,111"})
@Order(2)
void SuperTube_UserRepeatFail(String user,String login,String pass,String pass2,String age,String qq,String em) throws InterruptedException, IOException {
driver.findElement(By.cssSelector("#username")).sendKeys(user);
driver.findElement(By.cssSelector("#loginname")).sendKeys(login);
driver.findElement(By.cssSelector("#password")).sendKeys(pass);
driver.findElement(By.cssSelector("#password2")).sendKeys(pass2);
driver.findElement(By.cssSelector("#age")).sendKeys(age);
driver.findElement(By.cssSelector("#qq")).sendKeys(qq);
driver.findElement(By.cssSelector("#email")).sendKeys(em);
driver.findElement(By.cssSelector("#btn_sub")).click();
Thread.sleep(1000);
getScreenShot(getClass().getName());
}
/**
* @return void
* @description :管理員權(quán)限為超管,填寫用戶信息時,如果用戶名不重復(fù),可以提交。
*/
@ParameterizedTest
@CsvSource({"111,111,20,111,111"})
@Order(3)
void SuperTube_UserRepeatSucc(String pass,String pass2,String age,String qq,String em) throws InterruptedException, IOException {
Random random = new Random();
int n = random.nextInt(100000);
driver.findElement(By.cssSelector("#username")).sendKeys(String.valueOf(n));
driver.findElement(By.cssSelector("#loginname")).sendKeys(String.valueOf(n));
driver.findElement(By.cssSelector("#password")).sendKeys(pass);
driver.findElement(By.cssSelector("#password2")).sendKeys(pass2);
driver.findElement(By.cssSelector("#age")).sendKeys(age);
driver.findElement(By.cssSelector("#qq")).sendKeys(qq);
driver.findElement(By.cssSelector("#email")).sendKeys(em);
driver.findElement(By.cssSelector("#btn_sub")).click();
Thread.sleep(1000);
Alert alert = driver.switchTo().alert();
alert.accept();
Thread.sleep(1000);
Alert alert2 = driver.switchTo().alert();
alert2.dismiss();
Thread.sleep(1000);
getScreenShot(getClass().getName());
driver.navigate().back();
}
/**
* @return void
* @description: 返回鏈接跳轉(zhuǎn)正常。
*/
@Test
@Order(4)
void ReturnLinkJumpSucc() throws InterruptedException, IOException {
driver.findElement(By.cssSelector("#btn_back")).click();
driver.findElement(By.cssSelector("#body > div > h3"));
Thread.sleep(1000);
getScreenShot(getClass().getName());
}
}
3.5 測試修改用戶頁
創(chuàng)建 UpdateUserTest 類,該類的測試用例有 5 個(默認登錄狀態(tài)下)。文章來源:http://www.zghlxwxcb.cn/news/detail-418356.html
- 頁面內(nèi)容是否顯示正常。
- 管理員權(quán)限為超管,修改用戶信息時,如果密碼和確認密碼欄不相同,不能提交。
- 管理員權(quán)限為超管,修改用戶信息時,如果密碼和確認密碼欄相同,可以提交。
- 管理員權(quán)限為普通用戶,可以正常修改信息,但不能提交。
- 返回鏈接跳轉(zhuǎn)正常,重置按鈕功能正常。
/**
* @Description: 測試修改用戶頁
* @Date 2023/4/15 10:01
* @Author:
*/
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UpdateUserTest extends AutoTestUtils {
public static EdgeDriver driver = createDriver();
@BeforeAll
static void baseControl() {
driver.get("http://47.108.57.239:8080/update.html?uid=3");
}
/**
* @return void
* @description 檢查頁面內(nèi)容顯示是否正常
*/
@Test
@Order(1)
void AddPageLoadRight() throws InterruptedException, IOException {
driver.findElement(By.cssSelector("#body > div > h3"));
String text = driver.findElement(By.cssSelector("#loginname")).getAttribute("value");
Assertions.assertEquals("111",text);
driver.findElement(By.cssSelector("#btn_sub"));
Thread.sleep(1000);
getScreenShot(getClass().getName());
}
/**
* @return void
* @description :管理員權(quán)限為超管,修改用戶信息時,如果密碼和確認密碼欄不相同,不能提交。
*/
@ParameterizedTest
@CsvSource({"1234,111,111666"})
@Order(2)
void SuperTube_PassInequalityFail(String pass,String pass2,String em) throws InterruptedException, IOException {
driver.findElement(By.cssSelector("#password")).sendKeys(pass);
driver.findElement(By.cssSelector("#password2")).sendKeys(pass2);
driver.findElement(By.cssSelector("#email")).sendKeys(em);
driver.findElement(By.cssSelector("#btn_sub")).click();
Thread.sleep(1000);
Alert alert = driver.switchTo().alert();
alert.accept();
Thread.sleep(1000);
getScreenShot(getClass().getName());
driver.findElement(By.cssSelector("#btn_reset")).click();
}
/**
* @return void
* @description :管理員權(quán)限為超管,修改用戶信息時,如果密碼和確認密碼欄相同,可以提交。
*/
@ParameterizedTest
@CsvSource({"234567,234567,1111111"})
@Order(3)
void SuperTube_PassIdenticalSucc(String pass,String pass2,String em) throws InterruptedException, IOException {
driver.findElement(By.cssSelector("#password")).sendKeys(pass);
driver.findElement(By.cssSelector("#password2")).sendKeys(pass2);
driver.findElement(By.cssSelector("#email")).sendKeys(em);
driver.findElement(By.cssSelector("#btn_sub")).click();
Thread.sleep(1000);
Alert alert = driver.switchTo().alert();
alert.accept();
getScreenShot(getClass().getName());
driver.navigate().back();
}
/**
* @return void
* @description: 返回鏈接跳轉(zhuǎn)正常。
*/
@Test
@Order(4)
void ReturnLinkJumpSucc() throws InterruptedException, IOException {
driver.findElement(By.cssSelector("#btn_back")).click();
String text = driver.findElement(By.cssSelector("#body > div > h3")).getText();
Assertions.assertEquals("用戶信息列表",text);
getScreenShot(getClass().getName());
}
}
3.6 未登錄狀態(tài)
創(chuàng)建 UserNoLoginTest 類,該類的測試用例有 3 個。文章來源地址http://www.zghlxwxcb.cn/news/detail-418356.html
- 跳轉(zhuǎn)到用戶列表頁。
- 跳轉(zhuǎn)到添加用戶頁。
- 跳轉(zhuǎn)到修改用戶頁。
/**
* @Description: 測試未登錄狀態(tài)下
* @Date 2023/4/15 10:01
* @Author:
*/
public class UserNoLoginTest extends AutoTestUtils {
public static EdgeDriver driver = createDriver();
/**
* @param :
* @return void
* @description 未登錄狀態(tài)跳轉(zhuǎn)到用戶列表頁
*/
@Test
void JumpUserListFail() throws InterruptedException, IOException {
driver.get("http://47.108.57.239:8080/list.html");
Thread.sleep(1000);
String text = driver.findElement(By.cssSelector("#body > div > h3")).getText();
Assertions.assertEquals("管理員登錄",text);
getScreenShot(getClass().getName());
}
/**
* @return void
* @description 未登錄狀態(tài)跳轉(zhuǎn)到添加用戶頁
*/
@Test
void JumpAddUserFail() throws InterruptedException, IOException {
driver.get("http://47.108.57.239:8080/add.html");
Thread.sleep(1000);
String text = driver.findElement(By.cssSelector("#body > div > h3")).getText();
Assertions.assertEquals("管理員登錄",text);
getScreenShot(getClass().getName());
}
/**
* @return void
* @description 未登錄狀態(tài)跳轉(zhuǎn)到修改用戶頁
*/
@Test
void JumpUpdateUserFail() throws InterruptedException, IOException {
driver.get("http://47.108.57.239:8080/update.html");
Thread.sleep(1000);
String text = driver.findElement(By.cssSelector("#body > div > h3")).getText();
Assertions.assertEquals("管理員登錄",text);
getScreenShot(getClass().getName());
}
}
4. 自動化測試項目總結(jié)
4.1 自動化測試項目實現(xiàn)步驟
- 根據(jù)自己的項目,用思維導(dǎo)圖的方式設(shè)計出UI自動化測試用例;
- 結(jié)合自己編寫的測試用例,使用 Selenium4 自動化測試工具和 Junit5 單元測試框框架,實現(xiàn) Web 自動化測試;
- 然后就是進行模塊劃分,主要是按照兩個包劃分,一個是工具類包,用來創(chuàng)建驅(qū)動對象和提供屏幕截圖方法,還有一個包是測試用例包,這個包下面的類是按照以頁面為單位編寫的測試代碼,避免了每個方法都要創(chuàng)建驅(qū)動對象的麻煩,最后將這些測試類加入到測試套件中。
- 注意不要等項目整個代碼寫完后再進行測試,最好是寫一部分代碼測試一下。比如我編寫代碼時寫完一個頁面的測試用例后,再進行測試。
4.2 當(dāng)前項目亮點
- 只創(chuàng)建一次驅(qū)動對象,避免每個用例重復(fù)創(chuàng)建驅(qū)動對象造成時間和資源的浪費
- 使用了 Junit5 中提供的注解:避免生成過多的對象,造成資源和時間的浪費,提高了自動化的執(zhí)行效率
- 測試套件:降低了測試人員的工作量,通過套件一次執(zhí)行所有要運行的測試用例
- 使用了等待:隱式等待+強制等待(提高了自動化運行效率,提高了自動化的穩(wěn)定性)
- 使用屏幕截圖:方便問題的追溯以及問題的解決
- 使用參數(shù)化:保持用例的簡潔,提高代碼的可讀性
到了這里,關(guān)于用戶管理系統(tǒng)-自動化測試的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!