# Your Coroutine Tests Are Flaky Because of Two Clocks

The real reason behind inconsistent results in your coroutine tests.

- **Source:** [ProAndroidDev - Medium](https://brifing.si/source/d9553fa9-7b72-4b9b-bc73-c6bf9a40dd5f)
- **Published:** 2026-08-16
- **Topic:** [Software & Engineering](https://brifing.si/c/engineering)
- **Original article:** <https://proandroiddev.com/your-coroutine-tests-are-flaky-because-you-have-two-clocks-running-dfc2382909af?source=rss----c72404660798---4>
- **On Brifing:** https://brifing.si/s/6a1cb8e9-4946-4aca-b293-23fc44b1f93c

## Common Cause of Flaky Tests

The most common cause of inconsistent results (flaky tests) in coroutine tests is that one part of the test runs on a virtual clock while another part runs on a real clock. Your test assumes these two clocks are the same, but they are not. This inconsistency causes different results in different environments (CI vs local).

## The Role of TestDispatcher

The runTest function creates a virtual clock using TestScope and TestCoroutineScheduler. This allows functions like delay() to be skipped instantly. However, when you switch to a different dispatcher using withContext(Dispatcher...) in your production code, you lose control of the test scheduler. This block starts running on a real thread pool, making timing non-deterministic.

## Race Condition Example

In a viewModel test, the loadTrackDetails function runs on Dispatchers.IO, while the assertion might run before the IO operation completes. On a fast machine, the test usually passes, but it may fail in a busy CI environment. This is a classic race condition example that severely affects your test reliability.

## Wrong Solutions

Temporary solutions like increasing test timeout or adding sleep() only mask the problem. These methods increase test duration and do not provide a real solution. Moreover, they prevent your tests from being deterministic. Junior developers might resort to such solutions, but the core issue remains unresolved.

## Correct Solution: Dispatcher Injection

As recommended by Android Developers documentation, you should inject your dispatchers into your classes. This allows you to use test dispatchers instead of real ones in tests. The IDispatcherProvider interface and DispatcherProvider implementation let you manage all dispatchers centrally.

## Solution with TestDispatcherProvider

The TestDispatcherProvider class provides StandardTestDispatcher or UnconfinedTestDispatcher for all dispatchers. This ensures that even when using withContext, you don't lose control of the test scheduler. While production uses Dispatchers.IO, tests continue to run on the same virtual clock, making your tests deterministic.

## StandardTestDispatcher vs UnconfinedTestDispatcher

StandardTestDispatcher queues coroutines and waits until you explicitly run them. This is ideal for testing debounce or timeout. UnconfinedTestDispatcher starts coroutines immediately and runs them until the first suspension point. It's more suitable for tests that don't require execution order control.

## Critical Step for Test Reliability

Dispatcher injection is a critical step to improve the reliability of your coroutine tests. This method ensures consistent results across different environments and optimizes test duration. It also makes your code more modular and testable. Adopting this best practice will enhance your project's quality in the long run.

## Sources covering this story

- https://proandroiddev.com/your-coroutine-tests-are-flaky-because-you-have-two-clocks-running-dfc2382909af?source=rss----c72404660798---4 — 

---

_Summary written by Brifing from the original reporting. Copyright in the original article belongs to its publisher; read the full piece at the link above._
