Testing

Unit tests

Unit tests use JUnit 4 + Kotlin Coroutines test. Run with:

./gradlew test

Key testing patterns:

// Coroutine rule
@get:Rule
val mainDispatcherRule = MainDispatcherRule()

// Test ViewModel
@Test
fun `load inbox returns threads`() = runTest {
    val repo = mock<EmailRepository>()
    whenever(repo.getInboxThreadsFlow(any())).thenReturn(flowOf(listOf(thread)))
    val vm = InboxViewModel(repo, ..., settings)

    advanceUntilIdle()

    assertThat(vm.state.value).isInstanceOf(InboxState.Success::class.java)
    assertEquals(1, (vm.state.value as InboxState.Success).threads.size)
}

Instrumentation tests

./gradlew connectedGithubDebugAndroidTest

Debugging

Logging

TagArea
AuthManagerAuth flow, sign-in/out
EmailRepositoryData layer operations
InboxViewModelInbox state
EmailDetailViewModelDetail view state
ActionQueueManagerPending action processing
RetrofitClientHTTP request logging (debug builds only)

Debug commands

# View logs for a specific tag
adb logcat -s InboxViewModel

# Check database contents
adb shell run-as com.shrivatsav.monomail
cd databases
# DB is encrypted — use Room's database inspector in Android Studio

# Check DataStore
adb shell run-as com.shrivatsav.monomail
cd shared_prefs

Navigation debugging

The BuildConfig.DEBUG flag sets the start destination directly to Screen.SignIn (skipping the welcome screen) for faster iteration. There's also a Screen.SampleCompose route (debug only) for previewing the compose screen.

Crash handling

Production crashes are captured by CrashHandler and displayed in CrashActivity. The stack trace is saved to {cacheDir}/last_crash.txt.

Manual testing checklist

Before submitting a PR:

← Adding a Feature CI/CD →