iT邦幫忙

2026 iThome 鐵人賽

DAY 28
0

配合分支:day28/start,Repo: 按我

沒有安全感,就把安全帽戴上!!其實這個專案默默寫了很多測試(包括 Android Test 和 Unit Test)!重新查看後發現一些弔詭的地方,例如這個測試:

fun export_readsOnceAndDoesNotSave_orChangeSourceEntries() {}

這個測試匯出的時候,只允許「讀取」不要有任何的寫入行為。主要透過一個假的 DiaryStore。丟進去真正的 DiaryExporter,再去檢查做 export() 時,搓了幾次 load() 搓了幾次 save()

先來看這個假的 RecordingDiaryStore 在幹麻。雖然的確可以檢測 DiaryExporter 做了幾次讀取、寫入。

https://ithelp.ithome.com.tw/upload/images/20260916/20141615NuJ1rLOOVl.png

但這行是左手丟右手,怎麼測試都會過,無法保證最後結果。

val sourceEntries = listOf(firstEntry, secondEntry)
val originalEntries = sourceEntries.toList()

// WT? 💀
assertEquals(originalEntries, sourceEntries)

這次調整假 Class,讓這個 load() 真的做點什麼。這次調整的方向更變態,帶假資料,也一並測試 load() 後回傳的行為,只要查證資料,就可以不用記數器。(但是讀取還是要有)

不過 save() 就比較尷尬了,有別的方式驗證,但因為 interface 契約的關係,就先丟 Error 出去吧。(也會掛掉)

https://ithelp.ithome.com.tw/upload/images/20260916/20141615psGYMksSyR.png

這段就可以作為 Source 餵進去就行了。

// Given:建立只讀匯出專用 fake,並記錄匯出前的來源集合
val diaryStore = ReadOnlyDiaryStore()
val originalEntries = diaryStore.sourceEntries.toList()
val diaryExporter = DiaryExporter(diaryStore)

由此一來,DiaryExporter 可以直接丟入想要測試的 Formatter,例如:純文字 Formatter。

// When:匯出已儲存日記
val exportedText = diaryExporter.export(PlainTextDiaryFormatter())

diaryExporter.export()PlainTextDiaryFormatter() 做的都是 真實動作。而 ReadOnlyDiaryStore 則是剛剛放進去的木馬,透過它可以來驗證是否真的有進行讀取,或是寫入。

其實原版的邏輯大致上也是這樣,這次要調整的部分在於驗證
這次有將 export() 出來的資料拿出來做對比。看一下 PlainTextDiaryFormatter() 做了啥。

override fun format(entries: List<DiaryEntry>): String {
	return entries.joinToString(separator = "\n\n") { diaryEntry ->
		"${diaryEntry.title}\n${diaryEntry.note}"
	}
}

就是將 Title 以及 Note 串起來。exportedText 應該要長 第一筆\n第一筆內容\n\n第二筆\n第二筆內容這樣。那個(\n 是換行啦)。來寫驗證的部分囉。

// Then:確認輸出正確、只 load 一次,且來源集合與日記值不變
val expectedText = "第一筆\n第一筆內容\n\n第二筆\n第二筆內容"
// 👇🏼 驗證輸出的字,是否符合預期
assertEquals(expectedText, exportedText)

// 👇🏼 Load 只做了一次
assertEquals(1, diaryStore.loadCallCount)

// 🤗 上面存了 originalEntries,而且是複製了一份的
//  兩個 List 要一樣
assertEquals(originalEntries, diaryStore.sourceEntries)
//  第一個 Data 要相同
assertEquals(originalEntries[0], diaryStore.sourceEntries[0])
//  第二個 Data 要相同
assertEquals(originalEntries[1], diaryStore.sourceEntries[1])

可以看出來更堅固了!最後就來跑跑看是否成功:

https://ithelp.ithome.com.tw/upload/images/20260916/201416154qa4BhOzGX.png


上一篇
[Day27] 輸出格式,說來就來
系列文
我的第一個手作りAndroid App!快樂學習物件導向程式設計!28
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言