文章目錄
- 一、功能測試
- 1.編寫測試用例
- 2.總結測試后發現的BUG
- 二、UI自動化測試
- 0.搭建測試環境
- 1. 創建公共類
- 2.注冊頁面UI自動化測試用例編寫
- 3.登錄頁面UI自動化測試用例編寫
- 4.用戶博客列表頁面自動化測試
- 5. 修改個信息頁面
- 6. 文章編輯頁面
- 7. 設置密保問題
- 發現bug
- 8. 所有用戶文章列表頁
- 9. 總結
- 三、性能測試
- 1.編寫性能測試腳本
- 設置參數化
- 2.創建測試場景
- 3.開始執行
- 簡單分析性能測試報告
- 運行的虛擬用戶圖表
- 點擊率表
- 吞吐量表
- 平均事務響應時間圖
- 系統資源圖表
一、功能測試
1.編寫測試用例
2.總結測試后發現的BUG
通過一系列的測試發現項目的以下bug:
- 上傳圖片功能
上傳圖片格式不正確直接跳轉而沒有提示,且圖片格式校驗不嚴謹 - 發布博客測試
文章正文為空,沒有提示文章內容為空 - 修改文章
在修改文章時點擊保存草稿沒有做校驗提示錯誤 - 修改密碼
原密碼錯誤,提示有問題 - 找回密碼
未提示驗證碼錯誤,新密碼格式為空 - 博客列表頁
未簡略顯示文章正文字數過多問題
二、UI自動化測試
0.搭建測試環境
使用Junit5+selenium對項目進行簡單的自動化測試。
引入Junit5和selenium依賴
<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>5.8.2</version><scope>test</scope>
</dependency>
<dependency><groupId>org.junit.platform</groupId><artifactId>junit-platform-suite</artifactId><version>1.8.2</version><scope>test</scope>
</dependency>
<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>
為了方便自動化測試,這里關閉了項目的驗證碼功能。
1. 創建公共類
為了避免在使用時頻繁創建Chrome驅動類,我們可以定義一個功能類使用單例創建驅動對象。公共類里包含了保存截圖的方法,方便測試截圖觀察。
public class AutoTestUtil {private static volatile ChromeDriver driver;private static final String IMG_SAVE_DIR = "./src/img/";private AutoTestUtil(){}public static ChromeDriver getDriver() {if (driver == null) {synchronized (AutoTestUtil.class) {if (driver == null) {ChromeOptions options = new ChromeOptions();options.addArguments("--remote-allow-origins=*");driver = new ChromeDriver(options);// 設置隱式等待driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));}}}return driver;}/*** 獲取格式化時間* @return*/private static List<String> getTime() {// 圖片文件按照 包名.類名.方法名_時間搓區分SimpleDateFormat fileFormat = new SimpleDateFormat("yyyyMMdd-HHmmssSS");// 圖片目錄按照天區分格式20230812SimpleDateFormat dirFormat = new SimpleDateFormat("yyyyMMdd");String fileName = fileFormat.format(System.currentTimeMillis());String dirName = dirFormat.format(System.currentTimeMillis());List<String> result = new ArrayList<>();result.add(dirName);result.add(fileName);return result;}/*** 截圖* @param testFuncName 對應函數名* @throws IOException*/public static void saveFileImg(String testFuncName) throws IOException {List<String> times = getTime();String fileName = IMG_SAVE_DIR+times.get(0)+"/"+ testFuncName+"_"+times.get(1)+".png";File file = driver.getScreenshotAs(OutputType.FILE);FileUtils.copyFile(file,new File(fileName));}
}
2.注冊頁面UI自動化測試用例編寫
在該測試中發現問題,找不到警告彈窗。異常信息:
因為我這里是采用的隱式等待,隱式等待是對彈窗不起作用的,代碼執行過快就會出現代碼執行到點擊彈窗確定按鈕,而彈窗還沒有出現。所以在點擊之前將一個1秒的強制等待即可解決問題。
編寫測試代碼:
- 通過
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
保證測試用例的執行順序 - 對應的多個異常注冊測試用例
- 一個成功注冊測試用例,通過檢測是否跳轉登錄頁面來判斷是否注冊成功
// 使用方法排序
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class RegAutoTest {private static ChromeDriver driver;@BeforeAllstatic void init() {driver = AutoTestUtil.getDriver();driver.get("http://120.25.124.200:7070/register.html");driver.manage().window().maximize();}/*** 檢查注冊頁面是否正確打開* 檢測點:注冊賬號按鈕是否顯示*/@Test@Order(1)void regCheckLoad() {driver.findElement(By.xpath("//*[@id=\"reg_submit\"]"));}/*** 異常注冊* @param username* @param password* @param confirmPass*/@ParameterizedTest@Order(2)@CsvSource({"null,admin,admin","admin,null,admin","admin,admin,null","admin,admin,add","hhy,hhy,hhy"})void regFail(String username,String password,String confirmPass) throws InterruptedException {WebElement usernameElement = driver.findElement(By.cssSelector("#reg_username"));WebElement passwordElement = driver.findElement(By.xpath("//*[@id=\"reg_password\"]"));WebElement confirmPassElement = driver.findElement(By.cssSelector("#confirm_pass"));if (!username.equals("null")) {usernameElement.sendKeys(username);}if (!password.equals("null")) {passwordElement.sendKeys(password);}if (!confirmPass.equals("null")) {confirmPassElement.sendKeys(confirmPass);}driver.findElement(By.xpath("//*[@id=\"reg_submit\"]")).click();Thread.sleep(2000);// 點擊警告彈窗的確認按鈕Alert alert = driver.switchTo().alert();alert.accept();usernameElement.clear();passwordElement.clear();confirmPassElement.clear();}/*** 正常注冊* @param username* @param password* @param confirmPass*/@Order(3)@ParameterizedTest@CsvSource({"admin,admin,admin"})void regSuccess(String username,String password,String confirmPass) throws InterruptedException {driver.findElement(By.cssSelector("#reg_username")).sendKeys(username);driver.findElement(By.cssSelector("#reg_password")).sendKeys(password);driver.findElement(By.xpath("//*[@id=\"confirm_pass\"]")).sendKeys(confirmPass);driver.findElement(By.cssSelector("#reg_submit")).click();// 檢測登錄頁面的元素來判斷是否注冊成功跳轉// 檢測登錄按鈕+注冊連接driver.findElement(By.xpath("//*[@id=\"submit\"]"));driver.findElement(By.xpath("/html/body/div[2]/div[5]/a[1]"));Thread.sleep(1500);}@AfterAllstatic void quit() {driver.quit();}}
自動化測試演示
執行完畢后7個用列全部完成
3.登錄頁面UI自動化測試用例編寫
根據測試用例編寫對應代碼:
- 通過截圖查看是否進入博客列表頁面
- 使用套件執行自動化測試代碼
@Suite
@SelectClasses(LogInAutoTest.class)
public class RunSuite {
}
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class LogInAutoTest {private static ChromeDriver driver;@BeforeAllstatic void init() {driver = AutoTestUtil.getDriver();driver.get("http://120.25.124.200:7070/login.html");driver.manage().window().maximize();}/*** 檢測登錄頁面是否正確打開* 檢測點:注冊鏈接、登錄按鈕*/@Test@Order(1)void loginCheckLoad() {driver.findElement(By.xpath("/html/body/div[2]/div[5]/a[1]"));driver.findElement(By.xpath("//*[@id=\"submit\"]"));}/*** 正常登錄* @param username* @param password*/@ParameterizedTest@CsvSource({"admin,admin","hhy,hhy"})@Order(3)void loginSuccess(String username,String password) throws IOException, InterruptedException {driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);driver.findElement(By.cssSelector("#password")).sendKeys(password);driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();// 強制等待避免誤截圖Thread.sleep(1000);//將登錄成功后的用戶博客列表頁面進行截圖AutoTestUtil.saveFileImg(getClass().getName());driver.findElement(By.xpath("/html/body/div[1]/span[4]/a[3]")).click();Thread.sleep(1000);Alert alert = driver.switchTo().alert();alert.accept();Thread.sleep(1000);alert.accept();}/*** 異常登錄* @param username* @param password*/@ParameterizedTest@CsvSource({"null,null","null,admin","admin,null","admin,123","hello,000"})@Order(2)void loginFail(String username,String password) throws InterruptedException {WebElement usernameElement = driver.findElement(By.xpath("//*[@id=\"username\"]"));WebElement passwordElement = driver.findElement(By.cssSelector("#password"));if (!"null".equals(username)) {usernameElement.sendKeys(username);}if (!"null".equals(password)) {passwordElement.sendKeys(password);}driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();// 強制等待防止彈窗未出現Thread.sleep(1000);Alert alert = driver.switchTo().alert();alert.accept();usernameElement.clear();passwordElement.clear();}@AfterAllstatic void quit() {driver.quit();}
}
自動化執行演示:
登錄自動化執行完畢后,8個用例全部執行成功,保存了用戶博客列表頁面的截圖。
4.用戶博客列表頁面自動化測試
- 未登錄的情況下通過檢測url是否是登錄頁面來判斷是否跳轉
- 正常登錄場景下通過直接訪問博客列表后,判斷是否存在寫博客鏈接和文章標題判斷是否正確打開
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UserBlogListAutoTest {private static ChromeDriver driver;@BeforeAllstatic void init() {driver = AutoTestUtil.getDriver();driver.manage().window().maximize();}/*** 未登錄訪問*/@Test@Order(1)void userBlogListFail() {driver.get("http://120.25.124.200:7070/user_blog_list.html");// 獲取當前頁面url,判斷未登錄情況下是否跳轉String url = driver.getCurrentUrl();Assertions.assertEquals("http://120.25.124.200:7070/login.html",url);}/*** 進行正確登錄* @param username* @param password*/@ParameterizedTest@CsvSource({"admin,admin"})@Order(2)void loginSuccess(String username,String password) {driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);driver.findElement(By.cssSelector("#password")).sendKeys(password);driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();}/*** 登錄后訪問* 檢測點:寫博客鏈接,用戶文章標題*/@Test@Order(3)void userBlogListSuccess() {driver.get("http://120.25.124.200:7070/user_blog_list.html");driver.findElement(By.xpath("/html/body/div[1]/span[4]/a[2]"));driver.findElement(By.cssSelector("body > div.content > div.mid > div.show > div > h4"));}@AfterAllstatic void quit() throws InterruptedException {// 注銷driver.findElement(By.xpath("/html/body/div[1]/span[4]/a[3]")).click();Thread.sleep(1000);Alert alert = driver.switchTo().alert();alert.accept();Thread.sleep(1000);alert.accept();driver.quit();}
}
自動化演示:
5. 修改個信息頁面
在進行修改信息頁面測試時,發現無法找到昵稱輸入框,已經做了隱式等待。排查發現修改信息是在新窗口打開的,所以要通過代碼切換窗口來處理。
通過句柄跳轉到用戶個人信息頁面
// 獲取博客列表頁面句柄String windows = driver.getWindowHandle();// 點擊修改資料鏈接driver.findElement(By.xpath("/html/body/div[2]/div[2]/div[1]/div[3]/a")).click();// 獲取所有頁面句柄Set<String> windowHandles = driver.getWindowHandles();for (String s : windowHandles) {if (!s.equals(windows)) {// 切換到用戶信息頁面driver.switchTo().window(s);}}
自動化測試代碼:
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UpdateUserInfoAutoTest {private static ChromeDriver driver;@BeforeAllstatic void init() {driver = AutoTestUtil.getDriver();}/*** 未登錄狀態下訪問用戶信息修改頁面*/@Test@Order(1)void updateUserInfoFail() {driver.get("http://120.25.124.200:7070/updateInfo.html");driver.manage().window().maximize();}/*** 進行正確登錄* @param username* @param password*/@ParameterizedTest@CsvSource({"admin,admin"})@Order(2)void loginSuccess(String username,String password) {driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);driver.findElement(By.cssSelector("#password")).sendKeys(password);driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();}/*** 登錄成功場景,修改個人昵稱*/@Order(3)@Testvoid updateUserInfoSuccess() throws InterruptedException {// 獲取博客列表頁面句柄String windows = driver.getWindowHandle();// 點擊修改資料鏈接driver.findElement(By.xpath("/html/body/div[2]/div[2]/div[1]/div[3]/a")).click();// 獲取所有頁面句柄Set<String> windowHandles = driver.getWindowHandles();for (String s : windowHandles) {if (!s.equals(windows)) {// 切換到用戶信息頁面driver.switchTo().window(s);}}Thread.sleep(1000);// 修改基本信息driver.findElement(By.cssSelector("#netName")).clear();driver.findElement(By.cssSelector("#netName")).sendKeys("網友");// 提交修改driver.findElement(By.xpath("//*[@id=\"submitInfo\"]")).click();// 點擊彈窗確認按鈕Thread.sleep(1000);Alert alert = driver.switchTo().alert();alert.accept();}/*** 登錄狀態上傳頭像錯誤格式,大小錯誤*/@Order(4)@ParameterizedTest@CsvSource({"C:\\Users\\HeHanYu\\Desktop\\code\\test.txt","C:\\Users\\HeHanYu\\Desktop\\壁紙\\wallhaven-d6eylg.jpg"})void updateUserPhotoFail(String filePath) throws InterruptedException {// 獲取文件上傳按鈕WebElement element = driver.findElement(By.cssSelector("#uploadImg"));// 指定路徑選擇文件element.sendKeys(filePath);// 點擊上傳頭像driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();Thread.sleep(800);// 回退driver.navigate().back();}/*** 頭像上傳成功* @throws InterruptedException*/@Order(5)@Testvoid updateUserPhotoSuccess() throws InterruptedException {// 獲取文件上傳按鈕WebElement element = driver.findElement(By.xpath("//*[@id=\"uploadImg\"]"));// 指定路徑選擇文件element.sendKeys("C:\\Users\\HeHanYu\\Desktop\\code\\Python.jpg");Thread.sleep(1500);// 點擊上傳頭像driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();// 回退driver.navigate().back();}@AfterAllstatic void quit() throws InterruptedException {// 注銷driver.findElement(By.xpath("/html/body/div[1]/span[4]/a[3]")).click();Thread.sleep(1000);Alert alert = driver.switchTo().alert();alert.accept();Thread.sleep(1000);alert.accept();driver.quit();}}
自動測試執行完成后,測試用例全部通過
自動化測試演示:
6. 文章編輯頁面
根據用例編寫代碼
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ArticleEditorAutoTest {private static ChromeDriver driver;@BeforeAllstatic void init() {driver = AutoTestUtil.getDriver();}/*** 未登錄訪問*/@Order(1)@Testvoid notLogin() {driver.get("http://120.25.124.200:7070/blog_editor.html");}/*** 進行正確登錄* @param username* @param password*/@ParameterizedTest@CsvSource({"admin,admin"})@Order(2)void loginSuccess(String username,String password) {driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);driver.findElement(By.cssSelector("#password")).sendKeys(password);driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();}/*** 正確登錄場景下打開* 檢測點文章標題輸入框是否存在*/@Order(3)@Testvoid openArticleEditor() {// 點擊寫博客鏈接driver.findElement(By.cssSelector("body > div.nav > span.links > a:nth-child(2)"));// 直接輸入urldriver.get("http://120.25.124.200:7070/blog_editor.html");driver.manage().window().maximize();// 檢測頁面是否正確打開driver.findElement(By.cssSelector("#title"));}/*** 錯誤發布示例* @param title* @throws InterruptedException*/@ParameterizedTest@CsvSource({"null"})@Order(4)void postFail(String title) throws InterruptedException {if (!"null".equals(title)) {driver.findElement(By.cssSelector("#title")).sendKeys(title);}driver.findElement(By.xpath("/html/body/div[2]/div[1]/button[1]")).click();Thread.sleep(800);Alert alert = driver.switchTo().alert();alert.accept();}@ParameterizedTest@CsvSource({"博客標題"})@Order(5)void postSuccess(String title) throws InterruptedException {driver.findElement(By.cssSelector("#title")).sendKeys(title);driver.findElement(By.xpath("/html/body/div[2]/div[1]/button[1]")).click();Thread.sleep(800);Alert alert = driver.switchTo().alert();alert.accept();}@AfterAllstatic void quit() {driver.quit();}}
自動化演示:
博客發布頁面自動化測試用例全部通過
7. 設置密保問題
- 通過執行對應的錯誤測試用例
- 執行正確的測試用例設置密保問題后,去找回密碼頁面獲取密保問題
代碼編寫:
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class SetQuestionPasswordAutoTest {private static ChromeDriver driver;@BeforeAllstatic void init() {driver = AutoTestUtil.getDriver();}/*** 未登錄狀態下訪問*/@Order(1)@Testvoid notLogin() {driver.get("http://120.25.124.200:7070/set_questionPass.html");driver.manage().window().maximize();}/*** 進行正確登錄進入到修改密碼頁面* @param username* @param password*/@ParameterizedTest@CsvSource({"admin,admin"})@Order(2)void loginSuccess(String username,String password) throws InterruptedException {driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);driver.findElement(By.cssSelector("#password")).sendKeys(password);driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();Thread.sleep(500);driver.get("http://120.25.124.200:7070/set_questionPass.html");}/**** 錯誤設置* @param password* @param answerOne* @param answerTwo* @param answerThree* @throws InterruptedException*/@ParameterizedTest@CsvSource({"null,one,two,three","test,one,two,null","test,one,null,three","test,null,two,three","test,one,two,three"})@Order(3)void setQuestionPassFail(String password,String answerOne,String answerTwo,String answerThree) throws InterruptedException {WebElement passElement = driver.findElement(By.xpath("//*[@id=\"password\"]"));WebElement oneElement = driver.findElement(By.cssSelector("#oneValue"));WebElement twoElement = driver.findElement(By.xpath("//*[@id=\"twoValue\"]"));WebElement threeElement = driver.findElement(By.xpath("//*[@id=\"threeValue\"]"));if (!"null".equals(password)) {passElement.sendKeys(password);}if (!"null".equals(answerOne)) {oneElement.sendKeys(answerOne);}if (!"null".equals(answerTwo)) {twoElement.sendKeys(answerTwo);}if (!"null".equals(answerThree)) {threeElement.sendKeys(answerThree);}// 獲取Select問題標簽Select selectOne = new Select(driver.findElement(By.xpath("//*[@id=\"one\"]")));Select selectTwo = new Select(driver.findElement(By.xpath("//*[@id=\"two\"]")));Select selectThree = new Select(driver.findElement(By.xpath("//*[@id=\"three\"]")));// 選取問題selectOne.selectByIndex(1);selectTwo.selectByIndex(1);selectThree.selectByIndex(1);//提交driver.findElement(By.xpath("//*[@id=\"reg_submit\"]")).click();// 點擊彈窗確認按鈕Thread.sleep(500);driver.switchTo().alert().accept();// 清空輸入框passElement.clear();oneElement.clear();twoElement.clear();threeElement.clear();}/**** 正確設置* @param password* @param answerOne* @param answerTwo* @param answerThree* @throws InterruptedException*/@ParameterizedTest@CsvSource({"admin,one,two,three"})@Order(3)void setQuestionPassSuccess(String password,String answerOne,String answerTwo,String answerThree) throws InterruptedException {WebElement passElement = driver.findElement(By.xpath("//*[@id=\"password\"]"));WebElement oneElement = driver.findElement(By.cssSelector("#oneValue"));WebElement twoElement = driver.findElement(By.xpath("//*[@id=\"twoValue\"]"));WebElement threeElement = driver.findElement(By.xpath("//*[@id=\"threeValue\"]"));// 填寫密碼和問題passElement.sendKeys(password);oneElement.sendKeys(answerOne);twoElement.sendKeys(answerTwo);threeElement.sendKeys(answerThree);// 獲取Select問題標簽Select selectOne = new Select(driver.findElement(By.xpath("//*[@id=\"one\"]")));Select selectTwo = new Select(driver.findElement(By.xpath("//*[@id=\"two\"]")));Select selectThree = new Select(driver.findElement(By.xpath("//*[@id=\"three\"]")));// 選取問題selectOne.selectByIndex(1);selectTwo.selectByIndex(1);selectThree.selectByIndex(1);//提交driver.findElement(By.xpath("//*[@id=\"reg_submit\"]")).click();}/*** 檢測問題是否設置成功*/@Test@Order(4)void checkSetQuestion() throws InterruptedException {driver.get("http://120.25.124.200:7070/find_pass.html");Thread.sleep(1000);driver.switchTo().alert().accept();System.out.println(driver.getCurrentUrl());driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys("admin");driver.findElement(By.cssSelector("#reg > div:nth-child(1) > button")).click();String answer = driver.findElement(By.xpath("//*[@id=\"one\"]")).getText();System.out.println(answer);// 如果獲取到了問題說明設置密保問題就成功了Assertions.assertNotEquals("問題1",answer);}@AfterAllstatic void quit() {driver.quit();}
}
自動化演示:
發現bug
設置獲取的密保問題的斷言執行了。
在執行多次設置密保問后都設置成功了,但是在驗證通過密保問題找回密碼時,發生了錯誤。
通過查看數據庫的問題表發現了問題:
同一個用戶有多個問題存在數據表中,原因是設置密保問題時沒有對已經設置過密保的用戶進行校驗。導致多次插入數據,引發查詢到多條數據。
8. 所有用戶文章列表頁
在測試過程中發現為找到過期元素異常
發現是每次點擊上一頁或者下一頁,頁面都會刷新,所以導致元素失效,原理的代碼如下
@Testvoid test() throws InterruptedException {WebElement first = driver.findElement(By.cssSelector("body > div:nth-child(3) > div > button.first"));WebElement last = driver.findElement(By.xpath("/html/body/div[3]/div/button[4]"));WebElement front = driver.findElement(By.xpath("/html/body/div[3]/div/button[2]"));WebElement next = driver.findElement(By.xpath("/html/body/div[3]/div/button[3]"));first.click();Thread.sleep(1000);driver.switchTo().alert().accept();front.click();Thread.sleep(1000);driver.switchTo().alert().accept();next.click();Thread.sleep(1000);front.click();Thread.sleep(1000);last.click();Thread.sleep(1000);next.click();Thread.sleep(1000);driver.switchTo().alert().accept();last.click();Thread.sleep(1000);driver.switchTo().alert().accept();}
改進代碼,每次切換頁面后重新獲取元素
public class BlogListAutoTest {private static ChromeDriver driver;static WebElement first;static WebElement last;static WebElement front;static WebElement next;@BeforeAllstatic void init() {driver = AutoTestUtil.getDriver();driver.get("http://120.25.124.200:7070/blog_list.html");driver.manage().window().maximize();}void get() {first = driver.findElement(By.xpath("/html/body/div[3]/div/button[1]"));last = driver.findElement(By.xpath("/html/body/div[3]/div/button[4]"));front = driver.findElement(By.xpath("/html/body/div[3]/div/button[2]"));next = driver.findElement(By.xpath("/html/body/div[3]/div/button[3]"));}@Testvoid test() throws InterruptedException {get();first.click();Thread.sleep(1000);driver.switchTo().alert().accept();front.click();Thread.sleep(1000);driver.switchTo().alert().accept();next.click();get();Thread.sleep(1000);front.click();get();Thread.sleep(1000);last.click();get();Thread.sleep(1000);next.click();Thread.sleep(1000);driver.switchTo().alert().accept();get();last.click();Thread.sleep(1000);driver.switchTo().alert().accept();}@AfterAllstatic void quit() {driver.quit();}
}
自動化演示:
9. 總結
通過Junit5單元測試工具配合selenium4自動化工具有如下亮點(好處)
- 使用注解:避免生成過多對象,造成資源和時間的浪費
- 通過static修飾靜態變量,全局只創建一次驅動對象,避免重復創建驅動對象造成時間的浪費
- 使用參數化:保持用例簡潔,提高了代碼的可讀性
- 使用測試套件:一次性執行所有我們想要運行的自動化用例
- 使用等待(隱式等待+強制等待):提高自動化指定的穩定性(降低自動化出現誤報的概率)
- 使用屏幕截圖:方便問題的追溯和問題的解決
三、性能測試
使用LoadRunner對項目做一個簡單的性能測試,性能測試在本機上進行測試,測試云服務器太麻煩。
登錄和所有文章列表頁面是高頻使用場景,通過LoadRunner模擬多個用戶進行并發進行登錄后訪問所有文章列表頁面。
1.編寫性能測試腳本
Action()
{//開啟進入登錄頁事務lr_start_transaction("login_index");/* 注冊獲取返回參數,該方法可以配合打印返回數據,檢測數據內容 */web_reg_save_param("ParaResult","LB=","RB=",LAST);// 定時檢查點,檢測登錄頁面是否正確打開web_reg_find("Text=登錄",LAST);// 定義虛擬用戶結合點lr_rendezvous("start");// 進入登錄頁面web_url("login_html","URL=http://127.0.0.1:7070/login.html","TargetFrame=","Resource=0","Referer=",LAST);// 結束進入登錄頁事務lr_end_transaction("login_index", LR_AUTO);//開啟登錄事務lr_start_transaction("login");// 進行登錄web_submit_data("login","Action=http://127.0.0.1:7070/user/login","Method=POST","EncType=application/x-www-form-urlencoded; charset=UTF-8","TargetFrame=","Referer=","Mode=HTTP",ITEMDATA,"Name=username", "Value=<username>", ENDITEM,"Name=password", "Value=<password>", ENDITEM,LAST);//定時檢測所有文章列表頁檢查點web_reg_find("Text=查看全文",LAST);// 結束登錄事務lr_end_transaction("login", LR_AUTO);//文章列表事務lr_start_transaction("blog_list");// 登錄后訪問所有文章列表頁面web_url("blog_list","URL=http://127.0.0.1:7070/blog_list.html","TargetFrame=","Resource=0","Referer=",LAST);// 結束文章列表頁事務lr_end_transaction("blog_list", LR_AUTO);return 0;
}
點擊測試
測試腳本沒有問題后修改Action腳本的執行次數,執行5次腳本
設置參數化
為了保證測試的合理性,多個虛擬用戶使用多個不同的賬號進行登錄,使用LoadRunner的參數化即可實現。
2.創建測試場景
針對編寫好的腳本通過Controller創建測試場景
1.設置15個虛擬用戶
2.設置創建好測試場景后每5秒初始化3個虛擬用戶
3.設置每5秒進入3個虛擬用戶到測試場景
4.設置虛擬用戶執行循環執行5分鐘
5.設置虛擬用戶執行完畢后每10秒退出5個虛擬用戶
6.添加監視系統資源
CPU運行時間和剩余內存
3.開始執行
簡單分析性能測試報告
在事務報告中,一般只關注平均值和標準方差,標準偏差值越大,說明越不穩定。而且腳本里值是寫3個事務,而這里卻有6個,因為每個文件就是一個事務腳本文件中的(init、action、end)
運行的虛擬用戶圖表
通過虛擬用戶運行圖標發現,在腳本運行40秒到5分30秒之間虛擬用戶給了服務器負載
點擊率表
通過點擊率表可以看到和虛擬用戶運行表運行對應起來,虛擬用戶的增多點擊率也隨之增多,點擊率越多說明和服務器的交互次數也越多。
吞吐量表
吞吐量圖形和點擊數圖形有點相似,但是吞吐量的曲線會稍后延后一點遞增。因為吞吐量表示的是響應返回的資源數量,所有是要先有請求才會有響應。
平均事務響應時間圖
通過事務響應時間發現,訪問登錄頁面的時間比較長,登錄事務時間響應時間是比較短的,(深藍是訪問登錄頁面、黃色是登錄事務、粉紅色是進入文章列表頁面),在40秒的時候事務的響應時間達到最大,那個時候正是15個虛擬用戶生成完成,進行訪問服務,導致一大波請求到達服務,導致事務響應時間長。
虛擬用戶在性能測試過程中,每秒在服務器上命中的次數,通過次圖可以幫助根據命中次數評估虛擬用戶生成的負載量
系統資源圖表
- precessorTime:CPU使用時間,被消耗的處理器時間數量
- Available MBytes:可用的物理內存,一般根據這個指標推算消耗的物理內存有多大。(已經消耗的物理內存=實際內存 - 可用物理內存)
CPU的占用時間從30多秒開始,基本在長時間使用CPU,對CPU的使用時間還是長的。因為本地使用的是自己的電腦,而且并發設置了15,對于電腦壓力還是比較大的。
對應的這次測試對于內存的占用還不是特別高的。