Testing Strategy & Pyramid Quiz

TESTING › Strategy

According to the test pyramid, which type of test should you have the most of?

Answer: Unit tests

Unit tests form the base of the pyramid because they are fast, isolated, and stable, so you write many of them and far fewer slow UI tests.

Which statement best describes the tradeoff between local and instrumented tests?

Answer: Local tests run faster, while instrumented tests have higher fidelity.

Local JVM tests run quickly without a device, while instrumented tests run on a device/emulator with the real framework, giving higher fidelity at the cost of speed.

What is the recommended way to control coroutines when unit-testing a ViewModel?

Answer: Inject a test dispatcher and run the test with runTest

Injecting a TestDispatcher and using runTest gives deterministic, virtual-time control over coroutines, avoiding flaky sleeps and real-thread timing.

Which of these is the best candidate to NOT write a dedicated test for?

Answer: A trivial auto-generated data class with no custom logic

Trivial generated code with no logic provides little value to test; effort is better spent on your own logic, state changes, and edge cases.

When testing a ViewModel in isolation, how should its repository dependency typically be provided?

Answer: As a fake or test double that implements the repository interface

A fake implementation of the repository interface isolates the ViewModel from real I/O, keeping the test fast, deterministic, and a local test.

Which choice best distinguishes a fake from a mock?

Answer: A fake is a real working implementation; a mock is a scripted stub

A fake is a functional in-memory implementation you use normally, whereas a mock is a framework-configured object whose calls and return values you script and verify.

Why does keeping business logic out of Activities, Fragments, and the Android framework improve your test strategy?

Answer: It lets you swap dependencies and unit-test logic as fast tests

Decoupling logic from framework classes and using interfaces/DI lets you replace dependencies and verify logic in fast, isolated local tests rather than being forced into slow instrumented tests.

What is the key behavioral difference between UnconfinedTestDispatcher and StandardTestDispatcher in coroutine tests?

Answer: UnconfinedTestDispatcher starts eagerly; StandardTestDispatcher queues until advanced

UnconfinedTestDispatcher launches new coroutines eagerly and runs them until their first suspension, whereas StandardTestDispatcher defers them onto its scheduler until you advance virtual time.

You need to assert the exact sequence of values a Flow emits in a fast unit test. Which approach is most idiomatic?

Answer: Use Turbine to await and assert each item inside runTest

Turbine collects a Flow within runTest and lets you await each item deterministically, which is far more reliable than sleeping and sampling only the latest value.

What is Robolectric primarily used for?

Answer: Running Android framework tests on the host JVM without a device or emulator

Robolectric provides a simulated Android framework on the JVM, letting tests that touch SDK classes run as fast host-side tests instead of slow instrumented ones.

What do the integration tests in the middle of the test pyramid primarily verify?

Answer: That several layers collaborate, e.g. a repo and a real Room DB

Integration tests sit between unit and UI tests and confirm that several components wired together behave correctly, for example a repository plus its real DAO and database.

In a Jetpack Compose UI test, how do you locate and assert on a component?

Answer: Use createComposeRule, query the semantics tree, and assert on nodes

Compose tests use a compose test rule and query the semantics tree with finders like onNodeWithText, then chain assertions and actions on the matched node.

A module reports 95% line coverage. What can you correctly conclude from that number alone?

Answer: Lines ran in tests, but nothing about assertion quality or edge cases

Coverage only measures which lines ran during tests; code can be executed without any assertion verifying its behavior, so high coverage does not imply correctness or good edge-case handling.

Kotlin classes and methods are final by default. What does this imply when choosing a mocking approach?

Answer: Prefer MockK or Mockito inline, since final classes need special support

Because Kotlin classes are final unless marked open, plain Mockito cannot mock them without the inline mock maker; MockK is built for Kotlin and handles final classes out of the box.

Back to Testing Strategy & Pyramid