你的测试写全了吗?
QA設計的測試用例大部分都是面向業(yè)務的端到端測試,怎么能保證從DB來的數(shù)據(jù)通過層層service能順利的到達前端并被正確的展示出來呢?我們可以嘗試以UI和DB作為data flow的兩端串起所有的測試。
場景
想象一個典型的場景,一次sign off接近尾聲:
QA:這個些case都有測試嗎?
DEV:打開各種IDE,UT cover了case A,JT cover了case B,API test cover了case C
Sign off結束了,但是代碼里的測試真的覆蓋了QA預期的全部用例嗎?
假設一個系統(tǒng)的數(shù)據(jù)都存儲在DB中,而UI是系統(tǒng)與終端用戶交互的部分,那么數(shù)據(jù)在DB和UI之間通過各種service的互相調用而展示或存儲的過程就是一種data flow。
QA設計的測試用例大部分都是面向業(yè)務的端到端測試,怎么能保證從DB來的數(shù)據(jù)通過層層service能順利的到達前端并被正確的展示出來呢?我們可以嘗試以UI和DB作為data flow的兩端串起所有的測試。
舉個例子
某項目有一個叫FileSharing的website,用戶可以在上面共享文件。
系統(tǒng)的設計是FileSharing Frontend向FileSharing Backend發(fā)請求獲取file和user信息,FileSharing Backend向File Service發(fā)請求獲取file信息,File Service從DB讀取file信息。
其中一個需求是當前用戶可以看到自己和其他用戶上傳的文件,而他人上傳且未被該用戶下載過的文件名應該顯示為粗體。
根據(jù)這個需求設計出兩個test case:
- User should see new file in bold
- User should see downloaded(or upload by himself) file not in bold
以這兩個case為例,下圖展示了數(shù)據(jù)在代碼中的流動過程:
數(shù)據(jù)的流動方向是從DB到UI,檢查測試代碼可以先從數(shù)據(jù)消費終端的UI開始,目的是期望測試可以證明每一步正確處理和返回信息。
第一步:FileSharing Frontend
在file-store的測試文件里找到兩個相關測試
- should _be _shown _as _new _file
- should _not _be _new _file _after _download
并且通過file-store的代碼:
get isNew() {return !!this.isNewDocumentFromOthers; }可以知道需要后端返回isNewDocumentFromOthers
結論: 查看代碼已知file-store是前端頁面的數(shù)據(jù)源,這個測試是在file-store level,沒有測試保證html畫出來相應的item
第二步:FileSharing Backend
打開user的file頁面時,前端發(fā)了3個請求:
/files /user/types /user/verified根據(jù)上一步得到的信息可以知道/files就是要找的請求
{"id": "9a4af273-2d4e-4491-8f10-a93d2ba15e42","country": "US","fileName": "Instruction of FileSharing System","documentType": "Message","isNewDocumentFromOthers": true,"uploadedAt": "12/16/2019","uploadedBy": "ad77d3fc-e0af-499e-8a71-ab020073db34","year": 2000}在FileController的測試文件里找到一個測試
- should_ flag_ new_ files_ uploaded_ from_ others
并且通過FileController的代碼:
public bool IsNewDocumentFromOthers(Guid userId) {return IsUploadedFromOthers() && DocumentType != DocumentType.Consent &&(DownloadHistories == null ||DownloadHistories.ToList().TrueForAll(HasNotDownloadedByUser)); }可以知道FileSharing Backend需要File Service傳來IsUploadedFromOthers/DocumentType和DownloadHistory的信息
結論:這個測試是在API level,基本可以覆蓋當前測試用例,不過根據(jù)測試金字塔,API更多應該關注是否返回了需要的property,而property的值可以被下層的UT驗證
第三步:File Service
在FileController的測試文件里找到一個測試,但是只驗證了file的name/year/country
- should _get _by _user _id
結論:沒有驗證返回FileSharing Backend需要的IsUploadedFromOthers/DocumentType和DownloadHistory信息
測試覆蓋分析
整理以上的步驟可以得到下面的圖(標出了現(xiàn)有/缺失測試的部分)
如果從改善當前測試的角度出發(fā),能得到當前測試結構下的測試用例覆蓋表:
(綠色表示測試基本可以覆蓋用例,黃色表示有測試但是覆蓋不全,在這個例子里File Service需要驗證能返回正確的Uploadby/DocumentType和DownloadHistory的信息)
再從data flow的角度看可以發(fā)現(xiàn)更多問題:
- UI層面沒有對html做測試(風險較大)
- 現(xiàn)有的測試大部分集中在API層面,service層以下的UT測試比較少
- 服務之間缺乏契約測試導致修改一個API的時候只能人工檢查被影響的范圍
- 測試使用的內(nèi)存DB可能跟實際DB有差別(風險較小)
理想情況下,所有data經(jīng)過的地方都需要有測試保證data flow不會斷(數(shù)據(jù)被正確的處理和傳輸)。
改進
基于以上項目現(xiàn)狀,可以得出幾個投入產(chǎn)出比較高的action:
- 在signoff的時候DEV可以試著給QA說明現(xiàn)有代碼的結構,解釋數(shù)據(jù)流動的方式,幫助QA理解目前測試覆蓋的范圍,評估沒有測試的部分風險有多大,找出manual test的重點
- 后端service數(shù)據(jù)傳遞時如果是靠API測試驗證,則需要保證每個property都被測到
- 保證前端每個view model的行為和狀態(tài)都有JT cover
敏捷項目中開發(fā)寫測試所依據(jù)的理論主要是測試金字塔,但是測試本身該寫到哪一層并沒有明確的標準可以遵循,當試著跳出測試金字塔的理論,從數(shù)據(jù)這個根源沿著data flow去看現(xiàn)有的測試,就會有一些新的發(fā)現(xiàn),從根本上找出缺失或冗余的測試,確保測試做到更有效的覆蓋。
文/ThoughtWorks王蕾
總結
- 上一篇: 整数有约 | 光彻科技:AI智能体测系统
- 下一篇: 让金山词霸在 Adobe Reader