上一篇講了測試怎麼做,這一篇來寫測試
因為本篇內容都需要context所以都是使用instrumented test
因為這個應用的ViewModel已經和DataBase綁定了,因此寫起會比較複雜
@RunWith(AndroidJUnit4::class)
class MyDatabaseTest {
// Tests
}
首先生成一個模板,並在其中加入三個需要用到的變數
private lateinit var db: AppDatabase
private lateinit var dao: TodoDao
private lateinit var vm: GlobalVM
之後要先設定好開啟與結束
@Before
fun setup() {
val context = ApplicationProvider.getApplicationContext<Context>()
db = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
.allowMainThreadQueries()
.build()
dao = db.todoDao()
vm = GlobalVM(dao)
}
@After
fun teardown() {
db.close()
}
在Test裡面的context需要用Test模擬出的,之後用inMemoryBuilder,建立暫時的資料庫
在這裡的vm不需要使用factory初始化,直接參數丟入就好
fun insertAndRead() = runTest {
val todo1 = TodoItem(0, "a", "a", "1", true)
val todo2 = TodoItem(0, "b", "b", "2", true)
vm.submitTodo(todo1)
vm.submitTodo(todo2)
assertEquals(2, vm.getGroupInfo().first().size)
assertEquals("a", vm.getGroupTodo("1").first().first().title)
}
雖然更改功能還沒有時做在UI裡面,但這不妨礙先測試邏輯
@Test
fun change() = runTest {
val todo1 = TodoItem(0, "a", "a", "1", true)
val todo2 = TodoItem(0, "b", "b", "2", true)
vm.submitTodo(todo1)
vm.submitTodo(todo2)
assertEquals("a", vm.getGroupTodo("1").first().first().title)
val target = vm.getGroupTodo("1").first().first()
vm.focusTodo(target)
target.title = "c"
vm.submitTodo(target)
assertEquals("c", vm.getGroupTodo("1").first().first().title)
}
測試UI必須要有composeRule
@get:Rule
val composeTestRule = createComposeRule() // 宣告Compose Rule
這是Android的示範程式
@Test
fun counterTest() {
val myCounter = mutableStateOf(0) // State that can cause recompositions.
var lastSeenValue = 0 // Used to track recompositions.
composeTestRule.setContent {
Text(myCounter.value.toString())
lastSeenValue = myCounter.value
}
myCounter.value = 1 // The state changes, but there is no recomposition.
// Fails because nothing triggered a recomposition.
assertTrue(lastSeenValue == 1)
// Passes because the assertion triggers recomposition.
composeTestRule.onNodeWithText("1").assertExists()
}
從這邊就可以看出來,UI Test比一潘的邏輯測試牽扯的層面更多更廣,也因此不太好寫
var navController: TestNavHostController
這個可以模擬navController,但是需要引入dependency,這邊不多說
這邊是測試顯示還有按鈕有沒有用
@Test
fun testTodoBox() {
val todoItem = TodoItem(0, "a", "content", "A", true)
var check = false
composeTestRule.setContent {
TodoItemBox(
todoItem = todoItem,
onChecked = { check = it },
onModified = {},
onDelete = {}
)
}
// 1. 驗證文字有顯示
composeTestRule.onNodeWithText("a").assertExists()
composeTestRule.onNodeWithText("content").assertExists()
// 2. 驗證 checkbox 狀態正確 (因為 todoItem.done = true)
composeTestRule.onNode(isToggleable()) // Checkbox 是 toggleable
.assertIsOn()
// 3. 模擬點擊 checkbox
composeTestRule.onNode(isToggleable())
.performClick()
// 驗證 callback 被呼叫
assert(!check)
}
其實我一開始也有想要寫較大的UI test的,但是專案的各種資料嚴重耦合,所以難以測試
我大概說明