寫點有價值的測試用例


這篇文章為《解讀Android官方MVP項目單元測試》(以下簡稱《解讀》)的附錄部分,行此文的目的有二,其一是這個項目的單元測試齊全,覆蓋率很高,有極高的學(xué)習(xí)價值,筆者希望把每個測試用例都描述一遍,通過這種方式來強迫自己認(rèn)真的看完。其二,這部分內(nèi)容難免枯燥,筆者盡力想把它寫得可讀性高一點點,卻發(fā)現(xiàn)著實有難度,簡直是給自己挖坑,所以從《寫點有價值的測試用例》的角度出發(fā),對這篇附錄文章稍作修飾。但不管這樣,這個MVP項目及其單元測試用例對我們的工作可以帶來很多思路,所以不妨速讀一遍。

一 什么是有價值的測試用例

以這個項目為例,我覺得對于測試用例的設(shè)計,不能離開架構(gòu)層面和業(yè)務(wù)層面。

  1. 架構(gòu)層面
    不同的架構(gòu),決定著測試用例的寫法不一,比如MVC或者M(jìn)VP,每一層負(fù)責(zé)的測試職責(zé)是不一樣的。 以todo-mvp這個項目為例,筆者在《解讀》中已經(jīng)提到,一個功能的測試需要MVP三層的協(xié)作,彼此各司其職,卻又互相聯(lián)系,這里再做一番總結(jié):
  • Presenter層:這一層很清晰,我們?yōu)樗拿總€接口方法,以及每個方法里涉及的多個邏輯路徑設(shè)計相應(yīng)的測試用例,值得注意的是,這一層我們較少做輸入輸出的斷言,而是驗證是否正確覆蓋V層和M層的邏輯。
  • Model層:同上,我們?yōu)樗拿總€方法設(shè)計測試用例,與P層不同,這一層要斷言輸入輸出數(shù)據(jù)是否準(zhǔn)確。
  • View層:這一層我們放在業(yè)務(wù)層面來講。
  1. 業(yè)務(wù)層面
    做單元測試,測試業(yè)務(wù)邏輯是重中之重。View層承擔(dān)著這一重任,設(shè)計這一層的測試用例時,不要想太多,站在我們正常使用功能的角度出發(fā),把交互行為翻譯成Espresso的代碼。由于View是入口,當(dāng)一種交互行為發(fā)生,Presenter開始調(diào)度View和Model層各自執(zhí)行邏輯,因此從這個角度來講,View層的測試涵蓋了MVP三層的邏輯。

聊完有價值的,我們再來看看什么是沒價值的測試用例。比如以下幾種:

  1. 對成熟的工具類進(jìn)行測試
  2. 對簡單的方法進(jìn)行測試(比如get、set方法)
  3. MVP各層重復(fù)測試,比如P層去斷言輸入輸出的正確性

接下來筆者將完整的展示這個MVP項目中的所有單元測試用例,分為三個維度,androidTest下的、androidTestMock下的和test下的所有測試用例,如果覺得閱讀起來枯燥,可以直接閱讀每個測試類開篇的概述部分

二 androidTest文件下的測試

V層:導(dǎo)航界面測試——AppNavigationTest

概述:該測試用例做導(dǎo)航測試,即對DrawerLayout打開、關(guān)閉、點擊Item后打開的Activity等功能進(jìn)行測試。
意義:告訴我們?nèi)绾螌rawerLayout設(shè)計有價值的測試用例。

  1. clickOnStatisticsNavigationItem_ShowsStatisticsScreen
    打開Left Drawer->點擊Statistics按鈕->斷言StatisticsActivity已經(jīng)打開
  2. clickOnListNavigationItem_ShowsListScreen
    打開Left Drawer->點擊Statistics按鈕->打開Left Drawer->點擊TO-DO list按鈕->斷言TasksActivity已經(jīng)打開
  3. clickOnAndroidHomeIcon_OpensNavigation
    驗證通過ActionBar的icon進(jìn)行關(guān)閉和打開Left Drawer

V層:任務(wù)模塊界面測試——TasksScreenTest

概述:該測試用例針對任務(wù)列表和任務(wù)詳情頁的界面功能測試,涵蓋所有頁面上的交互,包括增刪改查任務(wù)、改變?nèi)蝿?wù)狀態(tài),過濾任務(wù)列表等,除此之外還驗證了橫豎屏的交互對界面數(shù)據(jù)狀態(tài)的影響。
意義:告訴我們?nèi)绾卧O(shè)計有價值的功能界面測試用例。

  1. clickAddTaskButton_opensAddTaskUi
    點擊添加按鈕->斷言相應(yīng)Activity已經(jīng)打開
  2. addTaskToTasksList
    添加標(biāo)題1的TO-DO任務(wù)后回到列表頁->斷言標(biāo)題1存在
  3. editTask
    添加標(biāo)題1的TO-DO任務(wù)后回到列表頁->點擊此Item進(jìn)入查看頁面->點擊編輯按鈕->修改成標(biāo)題2->點擊保存->斷言標(biāo)題1不存在和標(biāo)題2存在
  4. markTaskAsComplete
    添加任務(wù)并點擊CheckBox設(shè)置為已完成->通過過濾器進(jìn)入All/Active/Completed視圖,斷言該任務(wù)是否存在
  5. markTaskAsActive
    測試標(biāo)記任務(wù)為Active狀態(tài),手法同上一點
  6. showAllTasks
    添加2個任務(wù)->進(jìn)入All視圖->斷言兩個任務(wù)在界面上存在
  7. showActiveTasks
    添加2個任務(wù)->進(jìn)入Active視圖->斷言兩個任務(wù)在界面上存在
  8. showCompletedTasks
    添加2個任務(wù)->標(biāo)記為已完成->進(jìn)入Completed視圖->斷言兩個任務(wù)在界面上存在
  9. clearCompletedTasks
    添加2個任務(wù)->標(biāo)記為已完成->點擊Clear completed按鈕->斷言兩個任務(wù)不存在
  10. createOneTask_deleteTask
    添加1個任務(wù)->點擊該任務(wù)進(jìn)入詳情頁->點擊刪除->斷言該任務(wù)不存在
  11. createTwoTasks_deleteOneTask
    創(chuàng)建2個任務(wù)->刪除第2個->斷言第1個存在且第2個不存在
  12. markTaskAsCompleteOnDetailScreen_taskIsCompleteInList
    創(chuàng)建1個任務(wù)->點擊該任務(wù)進(jìn)入詳情頁->標(biāo)記為已完成->回到列表頁->斷言該任務(wù)為選中狀態(tài)
  13. markTaskAsActiveOnDetailScreen_taskIsActiveInList
    創(chuàng)建1個任務(wù)->在列表頁標(biāo)記為已選中->進(jìn)入詳情頁標(biāo)記為未選中->回到列表頁->斷言該任務(wù)未被選中
  14. markTaskAsAcompleteAndActiveOnDetailScreen_taskIsActiveInList
    創(chuàng)建1個任務(wù)->在詳情頁觸發(fā)兩次checkbox的點擊- 回到列表頁->斷言該任務(wù)未被選中
  15. markTaskAsActiveAndCompleteOnDetailScreen_taskIsCompleteInList
    創(chuàng)建1個任務(wù)->標(biāo)記為已完成->在詳情頁觸發(fā)兩次checkbox的點擊- 回到列表頁->斷言該任務(wù)被選中
  16. orientationChange_FilterActivePersists
    創(chuàng)建1個任務(wù)->標(biāo)記為已完成->進(jìn)入Active視圖->驗證該任務(wù)不存在->切換橫豎屏->斷言該任務(wù)狀態(tài)與之前一致
  17. orientationChange_FilterCompletedPersists
    創(chuàng)建1個任務(wù)->標(biāo)記為已完成->進(jìn)入Completed視圖->驗證該任務(wù)存在->切換橫豎屏->斷言該任務(wù)狀態(tài)與之前一致

M層:本地數(shù)據(jù)庫操作測試——TasksLocalDataSourceTest

概述:對數(shù)據(jù)庫中處理Task的增刪改查、改變Task狀態(tài)等進(jìn)行測試。

意義:持久層的CRUD往往需要配合起來測試和斷言,此例很好的詮釋了這一點

  1. saveTask_retrievesTask
  • 測試目的:驗證保存Task到數(shù)據(jù)庫的邏輯
  • 測試用例:實例化Task對象->保存入庫->根據(jù)ID獲取Task->在回調(diào)函數(shù)中斷言與入庫的Task一致
  1. completeTask_retrievedTaskIsComplete
  • 測試目的:驗證將任務(wù)設(shè)置成完成狀態(tài)的邏輯
  • 測試用例:Task對象保存入庫->觸發(fā)完成任務(wù)的邏輯->根據(jù)ID獲取Task->在回調(diào)函數(shù)中斷言該Task已完成
  1. activateTask_retrievedTaskIsActive
  • 測試目的:驗證將任務(wù)設(shè)置為激活狀態(tài)的邏輯
  • 測試用例:mock一個回調(diào)對象callback->Task對象保存入庫->觸發(fā)完成任務(wù)的邏輯->觸發(fā)激活任務(wù)的邏輯->根據(jù)ID獲取Task->斷言callback執(zhí)行了onTaskLoaded的邏輯
  1. clearCompletedTask_taskNotRetrievable
  • 測試目的:驗證清除所有已完成任務(wù)的邏輯
  • 測試用例:mock三個回調(diào)函數(shù)對象,分別是callback1到3->保存任務(wù)1,任務(wù)2和任務(wù)3,其中任務(wù)1和任務(wù)2為completed狀態(tài),任務(wù)3為active狀態(tài)->清理所有已完成的任務(wù)->根據(jù)3個Task的ID分別獲取Task->斷言callback1和callback2執(zhí)行了onDataNotAvailable邏輯- >斷言callback3執(zhí)行onTaskLoaded邏輯
  1. deleteAllTasks_emptyListOfRetrievedTask
  • 測試目的:驗證刪除數(shù)據(jù)庫中所有任務(wù)的邏輯
  • 測試用例:保存任務(wù)->mock一個回調(diào)函數(shù)callback->刪除所有任務(wù)->獲取任務(wù)列表->斷言callback執(zhí)行了onDataNotAvailable的邏輯
  1. getTasks_retrieveSavedTasks
  • 測試目的:驗證獲取數(shù)據(jù)庫中所有任務(wù)的邏輯
  • 測試用例:保存2個任務(wù)->獲取任務(wù)列表->在回調(diào)函數(shù)中斷言這2個任務(wù)存在

三 androidTestMock文件下的測試

《解讀》一文中,筆者提到該文件夾主要的作用是對網(wǎng)絡(luò)請求進(jìn)行Fake,即不發(fā)出網(wǎng)絡(luò)請求,而是返回事先定義好的數(shù)據(jù)。

V層:新增編輯任務(wù)界面測試——AddEditTaskScreenTest

  1. errorShownOnEmptyTask
  • 測試目的:驗證保存或編輯任務(wù)時,如果輸入空標(biāo)題,會彈出Snackbar提示不能為空
  • 測試用例:打開詳情頁->輸入空標(biāo)題和空描述->點擊保存->通過Snackbar的消息內(nèi)容驗證Snackbar已顯示

V層:統(tǒng)計界面測試——StatisticsScreenTest

  1. Tasks_ShowsNonEmptyMessage
    打開統(tǒng)計界面->事先Fake兩條任務(wù)數(shù)據(jù),狀態(tài)分別為Completed和Active->斷言兩種統(tǒng)計欄目都已顯示

V層:任務(wù)詳情界面測試——TaskDetailScreenTest

概述:Fake出不同狀態(tài)的任務(wù)并在詳情頁進(jìn)行標(biāo)題、描述和狀態(tài)的斷言。
意義:指導(dǎo)我們?nèi)绾螌W(wǎng)絡(luò)請求數(shù)據(jù)進(jìn)行Fake。

  1. activeTaskDetails_DisplayedInUi
    Fake一條狀態(tài)為Active的任務(wù)->打開詳情頁->斷言標(biāo)題、描述、任務(wù)狀態(tài)
  2. completedTaskDetails_DisplayedInUi
    Fake一條狀態(tài)為Complete的任務(wù)->打開詳情頁->斷言標(biāo)題、描述、任務(wù)狀態(tài)
  3. orientationChange_menuAndTaskPersist
    橫豎屏的測試手法與TasksScreenTest中一致,不再贅述。

四 test文件夾下的測試

P層:新增編輯任務(wù)測試——AddEditTaskPresenterTest

概述:進(jìn)入Presenter層的測試后,我們不再去斷言輸入輸出了,取而代之的是,斷言是否正確的覆蓋了View層和Model層的邏輯。AddEditTaskPresenter共有三個方法,分別是createTaskupdateTaskpopulateTask,對應(yīng)增加、修改、展示任務(wù)的功能,其中增加任務(wù)涉及到成功和失敗的情況,因此有4個測試用例。
意義:這些Presenter層的測試可以教會我們?nèi)绾蜯ock,如何verify,如何測試異步回調(diào),以及如何完整的覆蓋Presenter層的所有邏輯路徑。

  1. saveNewTaskToRepository_showsSuccessMessageUi
    創(chuàng)建Presenter,執(zhí)行創(chuàng)建任務(wù)的邏輯->斷言Model層執(zhí)行了保存的邏輯->斷言View層執(zhí)行了顯示任務(wù)列表的邏輯
  2. saveTask_emptyTaskShowsErrorUi
    創(chuàng)建Presenter,執(zhí)行創(chuàng)建任務(wù)的邏輯,且任務(wù)Title為空->斷言View層執(zhí)行了展示error的邏輯
  3. saveExistingTaskToRepository_showsSuccessMessageUi
    此用例驗證的是update任務(wù)的邏輯,測試手法同1。
  4. populateTask_callsRepoAndUpdatesView
  • 測試目的:驗證詳情頁展示的任務(wù)信息是否正確
  • 測試用例:presenter執(zhí)行populateTask()->斷言執(zhí)行了getTask(),且參數(shù)正確->斷言回調(diào)函數(shù)執(zhí)行了正確的邏輯->斷言View層展示的是正確的Task數(shù)據(jù)

P層:統(tǒng)計功能測試——StatisticsPresenterTest

概述:該類的presenter接口比較簡單,只有一個入口方法start,執(zhí)行的是加載統(tǒng)計信息的邏輯,執(zhí)行過程中涉及幾個路徑:加載空任務(wù)列表,加載非空任務(wù)列表和數(shù)據(jù)不可用,分別對應(yīng)以下1,2,3點。

  1. loadEmptyTasksFromRepository_CallViewToDisplay
    斷言加載空任務(wù)列表
  2. loadNonEmptyTasksFromRepository_CallViewToDisplay
    斷言加載非空任務(wù)列表
  3. loadStatisticsWhenTasksAreUnavailable_CallErrorToDisplay
    斷言數(shù)據(jù)不可用

P層:任務(wù)詳情功能測試——TaskDetailPresenterTest

概述:該Presenter共有5個方法,分別是:

  • start:展示任務(wù)詳情,涉及三種路徑:展示Active任務(wù)、展示Compeled任務(wù)和展示非法ID的任務(wù),對應(yīng)1,2,3的測試用例
  • deleteTask:刪除任務(wù),對應(yīng)第4個測試用例
  • completeTask:完成任務(wù),對于第5個
  • activateTask:激活任務(wù),對應(yīng)第6個
  • editTask:編輯任務(wù),對應(yīng)第7個,編輯非法ID的任務(wù)對應(yīng)的測試用例為第8個
  1. getActiveTaskFromRepositoryAndLoadIntoView
  2. getCompletedTaskFromRepositoryAndLoadIntoView
  3. getUnknownTaskFromRepositoryAndLoadIntoView
  4. deleteTask
  5. completeTask
  6. activateTask
  7. activeTaskIsShownWhenEditing
  8. invalidTaskIsNotShownWhenEditing

P層:任務(wù)列表功能測試——TasksPresenterTest

概述,此TasksPresenter的測試與上一點類似,從接口方法出發(fā),此類共有10個接口方法,為此設(shè)計了8個測試用例,分別是展示All/Active/Completed的任務(wù)列表、點擊打開任務(wù)詳情頁、改變?nèi)蝿?wù)狀態(tài)等。

  1. loadAllTasksFromRepositoryAndLoadIntoView
  2. loadActiveTasksFromRepositoryAndLoadIntoView
  3. loadCompletedTasksFromRepositoryAndLoadIntoView
  4. clickOnFab_ShowsAddTaskUi
  5. clickOnTask_ShowsDetailUi
  6. completeTask_ShowsTaskMarkedComplete
  7. activateTask_ShowsTaskMarkedActive
  8. unavailableTasks_ShowsError

M層:數(shù)據(jù)操作門面類測試——TasksRepositoryTest

概述:該類的測試用例非常齊全,對于如何設(shè)計測試用例讓數(shù)據(jù)過期,如何讓數(shù)據(jù)取自本地或者網(wǎng)絡(luò)等測試技巧都有極高的學(xué)習(xí)價值。

  1. getTasks_repositoryCachesAfterFirstApiCall
  2. getTasks_requestsAllTasksFromLocalDataSource
  3. saveTask_savesTaskToServiceAPI
  4. completeTask_completesTaskToServiceAPIUpdatesCache
  5. completeTaskId_completesTaskToServiceAPIUpdatesCache
  6. activateTask_activatesTaskToServiceAPIUpdatesCache
  7. activateTaskId_activatesTaskToServiceAPIUpdatesCache
  8. getTask_requestsSingleTaskFromLocalDataSource
  9. deleteCompletedTasks_deleteCompletedTasksToServiceAPIUpdatesCache
  10. deleteAllTasks_deleteTasksToServiceAPIUpdatesCache
  11. deleteTask_deleteTaskToServiceAPIRemovedFromCache
  12. getTasksWithDirtyCache_tasksAreRetrievedFromRemote
  13. getTasksWithLocalDataSourceUnavailable_tasksAreRetrievedFromRemote
  14. getTasksWithBothDataSourcesUnavailable_firesOnDataUnavailable
  15. getTaskWithBothDataSourcesUnavailable_firesOnDataUnavailable
  16. getTasks_refreshesLocalDataSource
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,613評論 25 708
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,781評論 18 139
  • 寫在前面 關(guān)于MVP關(guān)于MVP的介紹很多,這不是本文的重點,這里列舉近期一些比較好的文章。 Android官方MV...
    geniusmart閱讀 33,003評論 23 349
  • like語句 1、sql: select * from brrps_mart_org_mapwhere part_...
    queenieyin閱讀 673評論 0 0