On this page
An AI-generated test that calls a function and asserts the result is "not null" adds coverage and no safety. Good tests encode behaviour: given this situation, the app must do that. AI can help enumerate situations, and you decide which behaviours matter.
Edge cases first, then tests
Prompts that produce useful tests
Here is CheckoutViewModel and its UiState. List the behaviours and edge cases worth testing:
user actions, success/failure paths, boundary values, concurrency (double taps), and
state after errors. Don't write code yet. Group them by priority.Write JUnit4 tests for cases 1, 2, 4 and 7 only.
Conventions: MainDispatcherRule from com.example.testing, runTest, FakeCartRepository
and FakePaymentRepository (no mocking libraries), backtick test names describing behaviour,
one behaviour per test, assert on uiState values only.Example result, reviewed
class CheckoutViewModelTest {
@get:Rule val mainRule = MainDispatcherRule()
@Test
fun `double tap on pay submits only one payment`() = runTest {
val payments = FakePaymentRepository(delayMs = 1_000)
val vm = CheckoutViewModel(FakeCartRepository(total = 49_900), payments)
vm.onPayClick(); vm.onPayClick()
advanceUntilIdle()
assertEquals(1, payments.submittedCount) // guards against duplicate charges
}
@Test
fun `payment failure keeps cart and shows retryable error`() = runTest {
val vm = CheckoutViewModel(FakeCartRepository(total = 49_900), FakePaymentRepository(fail = true))
vm.onPayClick(); advanceUntilIdle()
val state = vm.uiState.value
assertEquals(49_900, state.totalPaise)
assertTrue(state.error?.canRetry == true)
assertFalse(state.isProcessing)
}
}These are worth keeping: each protects a real business rule, and each fails if the behaviour regresses.
Recognising weak AI tests
| Smell | Example | Fix |
|---|---|---|
| Asserts nothing meaningful | assertNotNull(vm.uiState.value) | Assert specific state values |
| Mirrors the implementation | Recomputes the expected total with the same formula | Use known, hand-calculated values |
| Over-mocking | Verifies every repository call | Use fakes; assert outcomes |
| Flaky timing | Thread.sleep, real dispatchers | Test dispatchers, virtual time |
| Tests framework behaviour | Asserting Room or Retrofit internals in unit tests | Test your logic; integration tests elsewhere |
Check that tests can fail
Manually introduce a bug (flip a condition, remove a guard) and run the tests. At least one should fail. Mutation-testing tools automate this idea on the JVM, but even a few manual mutations reveal hollow tests quickly.
Where AI test generation pays off
Legacy code with no tests
AI drafts characterization tests capturing current behaviour before a refactor. See Refactoring Legacy Apps.
Mappers and validators
Table-driven tests of many input variations, with hand-checked expected values.
Edge-case discovery
The brainstorm step often surfaces cases the team missed, such as double taps, empty states and time zones.
Frequently asked questions
Should coverage targets drive AI test generation?
No. Coverage encourages hollow tests. Target behaviours and risks, and use coverage only to find untested risky code.
Can AI generate UI tests?
It can draft Compose UI tests and screenshot previews, but they need the same review: realistic states, stable selectors and meaningful assertions.
What about Android Studio's test generation?
Gemini in Android Studio can generate unit tests for a class. Treat the output as a draft, and apply the review steps above.
Conclusion
Use AI to enumerate edge cases and draft tests in your conventions, then curate them, prove they fail when code breaks, and delete hollow ones. Good AI-assisted tests protect behaviours, not coverage numbers.
Next step: use AI on failures in Debugging Android Errors with AI.
Official references
๐ฑ Apps built by Yunok Tech
Real Android apps on Google Play, free to download.
Walzi4K wallpapers for lock and home screenGet it โธ
NotiVaultNotification history: recover dismissed notificationsGet it โธ
Ready to build real Android applications?
AI coding tools multiply what you already know. The stronger your Kotlin, Compose and architecture foundation, the better you can judge, fix and ship what these tools suggest.
Move beyond theory and strengthen your Android development skills with Yunoktech's Android course. Learn core concepts, practical implementation, modern Android development techniques, and the reasoning behind building maintainable applications.
Explore the Android course and take your next step as an Android developer.