個人博客系統測試報告

文章目錄

  • 一、功能測試
    • 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自動化工具有如下亮點(好處)

  1. 使用注解:避免生成過多對象,造成資源和時間的浪費
  2. 通過static修飾靜態變量,全局只創建一次驅動對象,避免重復創建驅動對象造成時間的浪費
  3. 使用參數化:保持用例簡潔,提高了代碼的可讀性
  4. 使用測試套件:一次性執行所有我們想要運行的自動化用例
  5. 使用等待(隱式等待+強制等待):提高自動化指定的穩定性(降低自動化出現誤報的概率)
  6. 使用屏幕截圖:方便問題的追溯和問題的解決

三、性能測試

使用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,對于電腦壓力還是比較大的。
    對應的這次測試對于內存的占用還不是特別高的。
    在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/37883.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/37883.shtml
英文地址,請注明出處:http://en.pswp.cn/news/37883.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Stable Diffusion +EbSynth應用實踐和經驗分享

Ebsynth應用 1.安裝ffmpeg 2.安裝pip install transparent-background,下載模型https://www.mediafire.com/file/gjvux7ys4to9b4v/latest.pth/file 放到C:\Users\自己的用戶名.transparent-background\加一個ckpt_base.pth文件 3.秋葉安裝ebsynth插件,重啟webui 填寫項目基本…

Redis 持久化及集群架構

Redis 持久化及集群架構 本篇技術博文將深入探討 Redis 持久化機制的原理、配置和使用方式。我們將介紹兩種常用的持久化方式&#xff1a;RDB 持久化和 AOF 持久化。您將了解到它們的工作原理、優缺點以及如何根據需求選擇合適的持久化方式。 通過深入學習 Redis 持久化及集群…

Rest 優雅的url請求處理風格及注意事項

&#x1f600;前言 本篇博文是關于Rest 風格請求的應用和注意事項&#xff0c;希望能夠幫助到您&#x1f60a; &#x1f3e0;個人主頁&#xff1a;晨犀主頁 &#x1f9d1;個人簡介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以幫助到大家&#xff0c;您…

應急響應-Webshell

文章目錄 一、Webshell概述什么是WebshellWebshell分類基于編程語言基于文件大小/提供的功能多少 Webshell 檢測方法 二、常規處置方法三、技術指南1、初步預判2、 Webshell排查3、Web日志分析&#xff08;查找攻擊路徑及失陷原因&#xff09;4、系統排查4.1 Windows4.2 Linux …

CSS中的position屬性有哪些值,并分別描述它們的作用。

聚沙成塔每天進步一點點 ? 專欄簡介? static? relative? absolute? fixed? sticky? 寫在最后 ? 專欄簡介 前端入門之旅&#xff1a;探索Web開發的奇妙世界 記得點擊上方或者右側鏈接訂閱本專欄哦 幾何帶你啟航前端之旅 歡迎來到前端入門之旅&#xff01;這個專欄是為那…

通達OA SQL注入漏洞【CVE-2023-4166】

通達OA SQL注入漏洞【CVE-2023-4166】 一、產品簡介二、漏洞概述三、影響范圍四、復現環境POC小龍POC檢測工具: 五、修復建議 免責聲明&#xff1a;請勿利用文章內的相關技術從事非法測試&#xff0c;由于傳播、利用此文所提供的信息或者工具而造成的任何直接或者間接的后果及損…

C/C++ 標準模版庫STL(持續更新版)

標準模版庫STL <algorithm> 算法庫 max, min 用于找出一組值中的最大值和最小值 swap 用于交換兩個變量的值 sort 用于對一個范圍內的元素進行排序 lower_bound, upper_bound 用于在已排序的容器中查找元素的下界和上界 unique(a,an)-a 用于在一個范圍內刪除相鄰重…

新的 Python URL 解析漏洞可能導致命令執行攻擊

Python URL 解析函數中的一個高嚴重性安全漏洞已被披露&#xff0c;該漏洞可繞過 blocklist 實現的域或協議過濾方法&#xff0c;導致任意文件讀取和命令執行。 CERT 協調中心&#xff08;CERT/CC&#xff09;在周五的一份公告中說&#xff1a;當整個 URL 都以空白字符開頭時&…

在 docker 中快速啟動 Apache Hive

介紹 在偽分布式模式下&#xff0c;在Docker容器內運行Apache Hive&#xff0c;可以提供以下功能&#xff1a;快速啟動/調試/為Hive準備測試環境。 快速開始 1. 拉取鏡像 從DockerHub&#xff1a;https://hub.docker.com/r/apache/hive/tags中拉取鏡像。目前發布了3個鏡像&…

gitlab修改遠程倉庫地址

目錄 背景&#xff1a; 解決&#xff1a; 1.刪除本地倉庫關聯的遠程地址&#xff0c;添加新的遠程倉庫地址 2.直接修改本地倉庫關聯的遠程倉庫地址 3.打開.git隱藏文件修改遠程倉庫地址 4.拉取代碼報錯(git host key verification failed) 背景&#xff1a; 公司搬家&#…

數字圖像處理 - 圖像處理結合機器學習的應用示例

在本文中,特別關注樹葉分類機器學習技術的實現。我們的目標是演示如何利用機器學習算法來分析一系列葉子照片,從而實現準確分類并提供對植物領域有價值的算法。 圖像處理中機器學習的本質 機器學習使計算機能夠學習模式并根據視覺數據進行預測,徹底改變了圖像處理領域。在葉…

image has dependent child images

問題&#xff1a;很多none的鏡像無法被刪除 解決過程&#xff1a; 1、通過 docker image prune -f 提示可刪除為 0 2、直接進行刪除報錯&#xff1a; docker rmi 8f5116cbc201Error response from daemon: conflict: unable to delete 8f5116cbc201 (cannot be forced) - im…

銀河麒麟安裝php7.1.33

銀河麒麟V10兼容CentOS 8 安裝過程與CentOS類似。 TencentOS3.1安裝PHPNginxredis測試系統_樂大師的博客-CSDN博客 可以參考之前我寫的文章。 不過有2個細節不同&#xff0c;下面說下。 問題1&#xff1a;編譯錯誤提示“error:off_t undefined” 解決方法&#xff1a; 編…

TCP收發信息(C++)

目錄 一、介紹 二、收數據 三、發數據 一、介紹 tcp和udp的區別之一&#xff0c;即tcp是有連接的&#xff0c;udp是無連接的&#xff0c;udp收發數據的代碼可以獨立運行&#xff0c;tcp發數據前必須確保收數據的一方是打開的&#xff0c;否則無法建立連接。 二、收數據 tc…

宋浩線性代數筆記(五)矩陣的對角化

本章的知識點難度和重要程度都是線代中當之無愧的T0級&#xff0c;對于各種雜碎的知識點&#xff0c;多做題復盤才能良好的掌握&#xff0c;良好掌握的關鍵點在于&#xff1a;所謂的性質A與性質B&#xff0c;是誰推導得誰~

MyBatis的SqlSession使用步驟

對MyBatis的SqlSession理解 SqlSession是 MyBatis 框架中的一個接口&#xff0c;用于執行與數據庫相關的操作。它提供了一系列方法&#xff0c;用于查詢、插入、更新和刪除數據等數據庫操作。 SqlSession接口是通過SqlSessionFactory創建的&#xff0c;每個SqlSession實例都代…

Ubuntu22.04復現SHADEWACHER(手動安你就慢了)

因為我是打算跑TC數據集&#xff0c;所以跳過audit安裝。 我的Ubuntu使用的是清華源。 1. Parser Setup 1.1 g apt install g1.2 neo4j Ubuntu22.04換什么源都會導致無法定位軟件包&#xff0c;添加neo4j的官方源又會導致不信任的源。 22.04以下的版本&#xff0c;直接用命…

MySQL 根據多字段查詢重復數據

MySQL 根據多字段查詢重復數據 在實際的數據庫應用中&#xff0c;我們經常需要根據多個字段來查詢重復的數據。MySQL 提供了一些方法來實現這個功能&#xff0c;讓我們能夠快速準確地找到和處理重復數據。本文將介紹如何使用 MySQL 來根據多字段查詢重復數據&#xff0c;并提供…

SIFT 算法 | 如何在 Python 中使用 SIFT 進行圖像匹配

介紹 人類通過記憶和理解來識別物體、人和圖像。你看到某件事的次數越多,你就越容易記住它。此外,每當一個圖像在你的腦海中彈出時,它就會將該項目或圖像與一堆相關的圖像或事物聯系起來。如果我告訴你我們可以使用一種稱為 SIFT 算法的技術來教機器做同樣的事情呢? 盡管…

C語言——動態內存函數(malloc、calloc、realloc、free)

了解動態內存函數 前言&#xff1a;一、malloc函數二、calloc函數三、realloc函數四、free函數 前言&#xff1a; 在C語言中&#xff0c;動態內存函數是塊重要的知識點。以往&#xff0c;我們開辟空間都是固定得&#xff0c;數組編譯結束后就不能繼續給它開辟空間了&#xff0…