目錄
項目背景
項目功能
測試詳情
一、設計測試用例
二、功能測試步驟結果
1. 登錄頁面
2. 個人博客頁面
3. 博客詳情頁
4. 博客編輯頁
?三、自動化測試及測試結果
1. 測試環境
2.?登錄測試用例:
3. 個人詳情頁測試用例:
4. 寫博客并發布測試用例:
5. 校驗已發布博客標題 和 時間
6. 更多測試用例詳情:
發現的bug / 如何修復 / 修復時間?
一、注冊失敗:
二、登錄獲取不到驗證碼圖片
三、博客發布時間為 null
四、點贊數量不增加:
項目背景
? ? ?無論是對于開發人員還是學生而言,在掌握了新的技術或者遇到了?bug,長期堅持寫博客都是對于自己技術提升的關鍵 ,目前的記錄博客的網站例如:CSDN,掘金,月光,祖冬SEO等等。所以我在學習過程中也會在一些博客網站中記錄自己對新技術的理解,最近學習了Java生態中的一些主流的框架,所以構思了一個輕量的博客網站:愛搜Blog,做了一個簡易版的博客記錄平臺。
項目功能
? ? 愛搜平臺提供 用戶管理、文章管理、以及關鍵字搜索功能。
- ? ? 用戶模塊:用戶注冊賬號之后會將用戶登錄狀態以 session 方式將數據持久化 到 redis中,所以用戶不需要在同一時間內重復登錄,并且采用加鹽算法技術來存儲用戶設置的密碼,所以可以保證系統的安全性。
- ? ? 文章管理模塊:支持文章的增刪改查,文章發布時間,作者信息,用戶點贊,文章熱度等,并引入第三方庫實現 markdown 格式的轉換,采用分頁算法支持前端的主頁界面的分頁瀏覽功能。
- ? ? 搜索模塊:采用關鍵字模糊查詢的方式可以讓用戶在平臺中搜索自己想要瀏覽的文章,以便給用戶更好的體驗。
測試詳情
項目測試模塊
- 設計測試用例
- 功能測試步驟結果
- 自動化測試及測試結果
- 定位到的 bug
- 如何解決的 bug 及 bug 修復時間
一、設計測試用例
?測試用例設計詳情:https://xafb501sh16.feishu.cn/mindnotes/Z0aebWzGymWbLsnMeKScLtL2n7M?from=from_copylink
? ? 編寫自動化測試用例首先要進行測試用例的設計,之后針對設計的測試用例詳細展開代碼的編寫。
二、功能測試步驟結果
1. 登錄頁面
1.1 賬號或密碼為空
?1.2 賬號或密碼填寫錯誤
?1.3 填寫驗證碼為空 / 錯誤
?1.4 正確登錄操作跳轉到個人列表頁面(可對已發布博客 增刪改查)
?2. 個人博客頁面
2.1 正常登錄狀態下 (點擊主頁)
?2.2 未登錄狀態下只導航欄只顯示登錄按鈕
?3. 博客詳情頁
3.1 未登錄狀態下(不能為文章點贊,支持搜索功能 ,不能修改其他用戶博客)
3.2 登錄狀態下(導航欄顯示主頁 / 寫博客 / 我的 / 注銷, 并且可以為當前文章進行點贊 并支持搜索功能)
?4. 博客編輯頁
4.1 未登錄狀態導航欄不顯示 / 不支持 寫博客
4.2 登錄狀態點擊寫博客可進入 博客編輯頁
?4.3 博客標題 / 正文 為空 (不能發布當前創作博客)
?4.3 標題 / 正文 不為空 (點擊發布文章后提示是否繼續添加文章)
?4.4 點擊 否 跳轉到 個人博客列表頁面 (點擊 是 則繼續添加博客文章)
?三、自動化測試及測試結果
? ? ?1. 測試環境
? ? 編寫自動化測試用例是根據實際的業務場景決定的,所以自動化測試用例可以測試愛搜平臺的核心功能:注冊、登錄、查看文章詳情、刪除博客、寫博客并 發布、分頁瀏覽、用戶點贊等。
- 相關技術及環境:
- 編譯器:IDEA 2021
- 瀏覽器:Google Chrom??104.0.5112.81
- 驅動程序:ChromSetup.exe
- 自動化測試工具:selenium4、Junit5
- 測試項目的依賴:
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-params --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-params</artifactId><version>5.8.1</version><!-- <scope>test</scope>--></dependency><!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.8.2</version><!-- <scope>test</scope>--></dependency><!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-suite --><dependency><groupId>org.junit.platform</groupId><artifactId>junit-platform-suite</artifactId><version>1.9.1</version></dependency><!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>5.8.1</version><!-- <scope>test</scope>--></dependency><!-- https://mvnrepository.com/artifact/commons-io/commons-io --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version></dependency><dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>3.141.59</version></dependency>
自動化測試前置工作:
? (由于自動化測試需要頻繁得到 web驅動程序對象,并且執行完測試用例后需要關閉 Chrom瀏覽器,所以可以將創建驅動對象、關閉瀏覽器設置成前置和后置方法)
package ISearchblogtest;import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;public class InitAndEnd {static WebDriver webDriver;@BeforeAllstatic void setUp() {webDriver = new ChromeDriver();}@AfterAllstatic void tearDown() {webDriver.quit();}
}
? ? ?注:以下測試用例用到了@order注解,不用 care(是因為先把 愛搜平臺的核心功能先按照順序整體進行了測試,然后又把所有的測試用例補充了細節)
2.?登錄測試用例:
? ? (由于測試驗證碼需要引入一些 OCR引擎,此處采用手工測試)
2.1?登錄成功:
對于正常登錄而言,編寫自動化測試用例需要進行傳遞多組測試用例參數,所以單獨在 resource配置文件下新建 loginSuccess.csv 文件:(然后將多組參數寫成多行的格式即可 idea 會自動識別csv文件中的參數,但是前提是加上@ParameterizedTest 和?@CsvFileSource(resources = "LoginSuccess.csv") 注解)
jiaoao,123,http://62.234.216.147:8080/myblog_list.html
/** 輸入正確的賬號,密碼, 驗證碼 登錄成功* */@Order(1)@ParameterizedTest@CsvFileSource(resources = "LoginSuccess.csv")void LoginSuccess(String username, String password, String blog_list_url) throws InterruptedException {//打開博客登錄頁面webDriver.get("http://62.234.216.147:8080/login.html");webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);//輸入賬號jiaoaowebDriver.findElement(By.cssSelector("#username")).sendKeys(username);//輸入密碼 123webDriver.findElement(By.cssSelector("#password")).sendKeys(password);//webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 輸入驗證碼 (注:此處采用手工測試)
// File imageFile = new File("D:/home/image/");
// File[] files = imageFile.listFiles();
// if (files != null && files.length > 0) {
// Arrays.sort(files, Comparator.comparing(File::lastModified));
// File lastImage = files[files.length - 1];
// if (lastImage.getName().endsWith(".png")) {
//
// } else {
// System.out.println("沒有找到當前要找的圖片!");
// }
// } else {
// System.out.println("當前文件夾為空!");
// }
// webDriver.findElement(By.cssSelector("#code_input")).sendKeys();sleep(9000);//點擊提交按鈕webDriver.findElement(By.cssSelector("#submit")).click();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 跳轉到列表頁//獲取到當前頁面的 url 如果url 是正確的則測試通過sleep(1000);String cur_url = webDriver.getCurrentUrl();Assertions.assertEquals(blog_list_url, cur_url);//列表頁展示用戶信息是jiaoao//用戶名是 jiaoao 則測試通過webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);webDriver.findElement(By.cssSelector("#artlist > div:nth-child(1) > a:nth-child(4)")).click();String cur_admin = webDriver.findElement(By.cssSelector("#author2")).getText();Assertions.assertEquals(username, cur_admin);System.out.println("登錄頁面通過自動化測試");}
測試用例執行結果:
?2.2?登錄異常:
jiaoao,11111,http://62.234.216.147:8080/login.html
// 測試異常登錄情況@Test@ParameterizedTest@CsvFileSource(resources = "LoginFile.csv")void loginFile(String username, String password, String blog_list_url) throws InterruptedException {webDriver.get("http://62.234.216.147:8080/login.html");webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);//輸入賬號jiaoaowebDriver.findElement(By.cssSelector("#username")).sendKeys(username);//輸入密碼 123webDriver.findElement(By.cssSelector("#password")).sendKeys(password);sleep(9000);//點擊提交按鈕webDriver.findElement(By.cssSelector("#submit")).click();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 跳轉到列表頁//獲取到當前頁面的 url 如果url 是正確的則測試通過sleep(1000);Alert alert = webDriver.switchTo().alert();alert.accept();String cur_url = webDriver.getCurrentUrl();Assertions.assertEquals(blog_list_url, cur_url);System.out.println("登錄頁面失敗通過自動化測試! [用戶名或密碼錯誤]");}
測試用例執行結果:
?3. 個人詳情頁測試用例:
@Order(2)@Testvoid BlogList() throws InterruptedException {//打開博客登錄頁面webDriver.get("http://62.234.216.147:8080/login.html");webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);//輸入賬號jiaoaowebDriver.findElement(By.cssSelector("#username")).sendKeys("jiaoao");//輸入密碼 123webDriver.findElement(By.cssSelector("#password")).sendKeys("123");sleep(9000);//點擊提交按鈕webDriver.findElement(By.cssSelector("#submit")).click();//跳轉到博客列表頁//獲取頁面上所有的博客標題對應的元素webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);webDriver.findElement(By.cssSelector("#artlist > div > a:nth-child(4)")).click();//用戶登錄信息和 博客詳情信息可以對應上String author = webDriver.findElement(By.cssSelector("#author2")).getText();Assertions.assertEquals("jiaoao", author);System.out.println("個人列表頁測試用例通過");}
測試用例執行結果:?
?4. 寫博客并發布測試用例:
?此處用到了 Generator()方法來獲取參數測試用例中用到的參數
public static Stream<Arguments> Generator() {return Stream.of(Arguments.arguments("http://62.234.216.147:8080/blog_content.html?id=","這是自動化測試第二篇博客!","一般是指軟件測試的自動化,軟件測試就是在預設條件下運行系統或應用程序,評估運行結果,預先條件應包括正常條件和異常條件。"));}
//測試寫博客@Order(4)@ParameterizedTest@MethodSource("Generator")void BlogDetail(String expected_url, String expected_title, String expected_blog) throws InterruptedException {//打開博客登錄頁面webDriver.get("http://62.234.216.147:8080/login.html");webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);//輸入賬號jiaoaowebDriver.findElement(By.cssSelector("#username")).sendKeys("jiaoao");//輸入密碼 123webDriver.findElement(By.cssSelector("#password")).sendKeys("123");sleep(8000);//點擊提交按鈕webDriver.findElement(By.cssSelector("#submit")).click();sleep(1000);// 點擊寫博客webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)")).click();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 輸入文章標題webDriver.findElement(By.cssSelector("#title")).sendKeys(expected_title);sleep(4000);// 點擊發布文章webDriver.findElement(By.cssSelector("body > div.blog-edit-container > div.title > button")).click();sleep(2000);Alert alert = webDriver.switchTo().alert();alert.dismiss();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);//找到第一篇博客對應的查看全文按鈕webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);webDriver.findElement(By.cssSelector("#artlist > div:nth-child(1) > a:nth-child(4)")).click();//獲取當前頁面的 url 獲取當前頁面 title 獲取博客標題webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);String cur_url = webDriver.getCurrentUrl();String cur_title = webDriver.getTitle();String cur_blog_title = webDriver.findElement(By.cssSelector("#title")).getText();if (cur_url.contains(expected_url)) {System.out.println("測試通過![url正確]");} else {System.out.println("測試不通過![url錯誤]");}sleep(3000);if (cur_title.contains("博客正文")) {System.out.println("測試通過![標題正確]");} else {System.out.println("測試不通過![標題錯誤]");}}
測試用例執行結果:??
?5. 校驗已發布博客標題 和 時間
@Order(5)@Testvoid BlogInfoCheck() throws InterruptedException {//打開博客登錄頁面webDriver.get("http://62.234.216.147:8080/login.html");webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);//輸入賬號jiaoaowebDriver.findElement(By.cssSelector("#username")).sendKeys("jiaoao");//輸入密碼 123webDriver.findElement(By.cssSelector("#password")).sendKeys("123");sleep(8000);//點擊提交按鈕webDriver.findElement(By.cssSelector("#submit")).click();sleep(1000);//獲取第一篇博客標題String first_blog_title = webDriver.findElement(By.cssSelector("#artlist > div:nth-child(1) > div.title")).getText();//獲取第一篇博客發布時間String first_blog_time = webDriver.findElement(By.cssSelector("#artlist > div:nth-child(1) > div.date")).getText();//校驗博客標題是否是 ”這是自動化測試第二篇博客!“Assertions.assertEquals("這是自動化測試第二篇博客!", first_blog_title);//如果時間是 2023-08 發布的,測試通過if (first_blog_time.contains("2023-08")) {System.out.println("當前時間匹配");System.out.println("測試通過");}else {System.out.println("當前時間不匹配");System.out.println("測試不通過!");}}
測試用例執行結果:??
6. 更多測試用例詳情:
? ? 上述自動化測試用例是一部分,包括測試通過是否執行通過,(所有測試用例已通過)愛搜平臺自動化測試用例更多詳情:Java進階學習: 自動化測試 - Gitee.com
發現的bug / 如何修復 / 修復時間?
bug修復時間:2023-8-16 ~?2023-8-18
當項目部署到云服務器后,更新了測試用例(自動化測試版本1只是測試單機項目,更新后的是測試的服務器中的項目),然后執行測試用例就出現了不少的 bug:
一、注冊失敗:
? ? 如下圖所示:
定位bug:
? ? 1. 觀察報錯信息,發現密碼長度過長,導致 Mariadb 中的數據表無法存儲這個密碼數據(仔細回想;雖然輸入的密碼只有三個數字,但是數據庫中存儲的是用加鹽算法處理過的密碼)
? ? 2. 對比MySQL中的password字段長度,以前在 MySQL 更改過用戶的信息表結構,發現在Mariadb 中沒有注意這個問題
解決方案:
? ? 修改 Mariadb 數據庫用戶表中 password 長度即可。
二、登錄獲取不到驗證碼圖片
? ? ?如下圖所示:
?定位bug:
? ? 1. 抓包工具看前端 Ajax 請求數據和參數是否正確發送,后觀察后端接口參數是否一個并且綁定
? ? 2. 發現響應的數據為 null,看后端存儲驗證碼的路徑對應的文件是否有生成的驗證碼圖片,發現后端 properties 配置文件錯誤,項目部署到云服務器中需要新創建文件夾存儲生成的驗證碼圖片
解決方案:
? ? 停止當前項目運行并殺死8080端口對應進程,之后修改項目配置文件中的驗證碼存儲路徑,重新打包項目,上傳至云服務器,創建對應的文件夾存儲驗證碼圖片,重啟項目,發現bug已解決
三、博客發布時間為 null
? ? 新發布的博客不顯示博客發布時間,如下圖所示:
定位bug:
? ? 使用 fiddler 抓包工具 觀察返回的響應信息,發現參數有誤;
? (1)觀察前端 Ajax 請求,確定不是前端的參數傳遞問題
? (2)檢查后端參數是否接收和綁定,是否使用 @Param 注解
? (3)檢查數據庫表 結構以及初始設置參數是否有誤,發現當前服務器中的 Mariadb5.5版本及以下 數據庫不支持 timestamp 類型,而且不允許設置默認值
解決方案:
? ? 1. 更改服務器中 Mariadb 版本為 10.0 以上版本(配置阿里云鏡像文件)詳情可以參考這位大佬博客:網站運維:Centos7使用yum安裝最新MariaDB 10.4.6 -CSDN博客?和?MariaDB 5.5 create table default value 注意的事項_mariadb不能插入月份-CSDN博客
中間遇到關于 Mariadb 不能免密登錄的問題可參考:Mariadb和mysql 忘記root密碼,初始化密碼 - 知乎mariadb和mysql都是數據庫 1,重置密碼2,修改密碼3,忘記密碼怎么修改1.mariadb 第一安裝進去是不需要密碼的 直接敲 mysql 就可以直接進去 這時候是沒有密碼的給root設置密碼 如果你已經設置過密碼,想要修改密碼…https://zhuanlan.zhihu.com/p/112774485#:~:text=1%2C%20%E6%89%BE%E5%88%B0mariadb%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%20%E4%B8%80%E8%88%AC%E5%9C%A8%20%2Fetc%2Fmy.cnf%20%E6%8A%8A%20skip-grant-tables%20%E6%B7%BB%E5%8A%A0%E5%88%B0%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E9%87%8C%E9%9D%A2%20%E6%94%BE%E5%9C%A8%5Bmysqld%5D%E4%B8%8B%E9%9D%A2%E5%B0%B1%E5%8F%AF%E4%BB%A5%E4%BA%86,systemctl%20restart%20mariadb%206%20%E7%99%BB%E5%BD%95%E5%B0%B1%E5%8F%AF%E4%BB%A5%E4%BA%86%20mysql%20-uroot%20-p%27%E8%AE%BE%E7%BD%AE%E7%9A%84%E6%96%B0%E5%AF%86%E7%A0%81%27? ? 2. 更改表結構,設置 發布博客時間 參數類型,并設置默認值為當前時間
? ? 3. 重啟 Mariadb 數據庫,將項目重新打包部署到云服務器
四、點贊數量不增加:
當跳轉到文章詳情頁時,如果時已經登錄的用戶,是可以對文章點贊的,但是登陸后發現點擊點贊按鈕后,點贊數量并不會增加,如下圖所示:
?定位bug:
? ? 1. 使用 fiddler 抓包工具查看請求數據和參數是否和數據庫字段值對應(這里前端的參數,包括后端的參數和數據庫的參數防止容易出錯,直接使用的都是同一的參數)
? ? 2. 點擊點贊按鈕,抓包看點贊操作的接口是否能夠發送請求,發現沒有 upvote(點贊) 接口
? ? 3. 查看后端響應的數據是否正確,使用瀏覽器抓包后,顯示當前返回的響應 data 中 value 值為 null
? ? 4. 查看數據庫表字段及設置的默認值是否正確,發現表結構中的 upvote字段沒有設置默認值 0,所以默認是 null
解決方案:
? ? 修改文章數據表中的 isupvote(存儲點贊狀態)和 upvote_count(存儲點贊數量)字段默認值,修改為 int(0)即可,之后重啟 Mariadb 服務,發現bug已解決。