Add DueTodayViewModel Unit Tests

This commit is contained in:
Geoffroy Bonneville
2025-11-06 20:49:46 -05:00
parent 85f1e66a62
commit fc3672b17b
3 changed files with 114 additions and 0 deletions

BIN
donext.backup Normal file

Binary file not shown.

View File

@@ -80,6 +80,9 @@ dependencies {
implementation("androidx.navigation:navigation-compose:2.9.5") implementation("androidx.navigation:navigation-compose:2.9.5")
implementation("androidx.hilt:hilt-navigation-compose:1.3.0") implementation("androidx.hilt:hilt-navigation-compose:1.3.0")
implementation("sh.calvin.reorderable:reorderable:3.0.0") implementation("sh.calvin.reorderable:reorderable:3.0.0")
testImplementation("junit:junit:4.13.2")
testImplementation("io.mockk:mockk:1.13.12")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0")
androidTestImplementation("androidx.test.ext:junit-ktx:1.3.0") androidTestImplementation("androidx.test.ext:junit-ktx:1.3.0")
androidTestImplementation(platform("androidx.compose:compose-bom:2025.10.01")) androidTestImplementation(platform("androidx.compose:compose-bom:2025.10.01"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4") androidTestImplementation("androidx.compose.ui:ui-test-junit4")

View File

@@ -0,0 +1,111 @@
package com.wismna.geoffroy.donext.presentation.viewmodel
import com.wismna.geoffroy.donext.R
import com.wismna.geoffroy.donext.domain.model.Priority
import com.wismna.geoffroy.donext.domain.model.Task
import com.wismna.geoffroy.donext.domain.usecase.GetDueTodayTasksUseCase
import com.wismna.geoffroy.donext.domain.usecase.ToggleTaskDeletedUseCase
import com.wismna.geoffroy.donext.domain.usecase.ToggleTaskDoneUseCase
import com.wismna.geoffroy.donext.presentation.ui.events.UiEvent
import com.wismna.geoffroy.donext.presentation.ui.events.UiEventBus
import io.mockk.*
import junit.framework.TestCase.assertEquals
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.test.*
import org.junit.After
import org.junit.Before
import org.junit.Test
@OptIn(ExperimentalCoroutinesApi::class)
class DueTodayViewModelTest {
private lateinit var getDueTodayTasksUseCase: GetDueTodayTasksUseCase
private lateinit var toggleTaskDeletedUseCase: ToggleTaskDeletedUseCase
private lateinit var toggleTaskDoneUseCase: ToggleTaskDoneUseCase
private lateinit var uiEventBus: UiEventBus
private lateinit var viewModel: DueTodayViewModel
private val testDispatcher = StandardTestDispatcher()
private val tasksFlow = MutableSharedFlow<List<Task>>(replay = 1)
@Before
fun setup() {
Dispatchers.setMain(testDispatcher)
getDueTodayTasksUseCase = mockk()
toggleTaskDeletedUseCase = mockk(relaxed = true)
toggleTaskDoneUseCase = mockk(relaxed = true)
uiEventBus = mockk(relaxed = true)
coEvery { getDueTodayTasksUseCase.invoke() } returns tasksFlow
viewModel = DueTodayViewModel(
getDueTodayTasksUseCase,
toggleTaskDeletedUseCase,
toggleTaskDoneUseCase,
uiEventBus
)
}
@After
fun tearDown() {
Dispatchers.resetMain()
}
@Test
fun `dueTodayTasks updates when flow emits`() = runTest {
val taskList = listOf(Task(taskListId = 0, id = 1, name = "Test Task", description = "", priority = Priority.NORMAL, isDone = false, isDeleted = false))
tasksFlow.emit(taskList)
advanceUntilIdle()
assertEquals(taskList, viewModel.dueTodayTasks)
}
@Test
fun `onTaskClicked sends EditTask event`() = runTest {
val task = Task(taskListId = 0, id = 42, name = "Click me", description = "", priority = Priority.NORMAL, isDone = false, isDeleted = false)
viewModel.onTaskClicked(task)
advanceUntilIdle()
coVerify { uiEventBus.send(UiEvent.EditTask(task)) }
}
@Test
fun `updateTaskDone toggles done and sends snackbar with undo`() = runTest {
val taskId = 5L
viewModel.updateTaskDone(taskId)
advanceUntilIdle()
coVerify { toggleTaskDoneUseCase(taskId, true) }
coVerify {
uiEventBus.send(
match {
it is UiEvent.ShowUndoSnackbar &&
it.message == R.string.snackbar_message_task_done
}
)
}
}
@Test
fun `deleteTask toggles deleted and sends snackbar with undo`() = runTest {
val taskId = 7L
viewModel.deleteTask(taskId)
advanceUntilIdle()
coVerify { toggleTaskDeletedUseCase(taskId, true) }
coVerify {
uiEventBus.send(
match{
it is UiEvent.ShowUndoSnackbar &&
it.message == R.string.snackbar_message_task_recycle
}
)
}
}
}