Testing Isn’t a One‑Time Setup
Context: This post is part of the StreamBox branch‑by‑branch series.
Each branch adds one architecture concept and stops.
The app already had tests.
But they were uneven.
Some used fakes. Some used ad‑hoc coroutine setups.
Some verified outcomes, not behavior.
It worked.
It didn’t scale.
This branch is feature/unit-testing.
It doesn’t change the app.
It changes how we trust it.
The Problem This Branch Solves
Tests existed.
But the intent wasn’t consistent.
Fakes masked behavior.
Flow tests were shallow.
Coroutine tests were timing‑sensitive.
That’s not production‑grade.
That’s just “something exists.”
The Idea in One Line
> Tests should read like behavior, not like scaffolding.
Why Unit Testing Needed a Rethink
Architecture was already stable.
Reducers were predictable.
UseCases were focused.
Repositories were thin.
But test structure didn’t match that clarity.
So we fixed the test layer.
Not the runtime layer.
Learning From a Real Production Codebase
Large apps don’t rely on clever tests.
They rely on consistent ones.
Each layer owns its tests.
Each test states its intent.
Each test is deterministic.
That’s the standard this branch adopts.
Mocking with MockK
MockK was introduced for one reason — clarity.
Fakes stayed only when they made sense.
Mocks now verify behavior when it matters:
- UseCases
- Repositories
- Mediators
Not everything is mocked.
But when behavior matters, it is.
Testing Coroutines and Flows Correctly
Coroutine tests are easy to get wrong.
Delays hide real problems.
Timing creates flakiness.
Get Manish Dubey’s stories in your inbox
Join Medium for free to get updates from this writer.
So this branch uses:
- proper test dispatchers
- runTest
- Turbine for Flow
Fast. Deterministic. Repeatable.
Layer‑Specific Testing Strategies
Reducers:
- pure state transitions
Mappers:
- pure transformations
UseCases:
- orchestration intent
Repositories / Mediators:
- success + failure + fallback
UI and Compose:
- intentionally excluded
This is unit testing.
Not integration testing.
Testing Anti‑Patterns Avoided
This branch avoided the patterns that cause long‑term drift:
- excessive fakes that hide behavior
- delay‑based coroutine tests
- over‑mocking implementation details
- asserting internal state instead of outcomes
- treating coverage as a quality metric
- mixing unit tests with integration concerns
- Android framework dependencies in unit tests
These weren’t theoretical.
They were corrections.
Introducing Code Coverage with Kover
Coverage was added after tests improved. Not before.
Coverage is a signal. Not a goal.
Kover now highlights:
- untested paths
- false confidence
But it does not drive test bloat.
What Changed — and What Stayed Untouched
Changed:
- test structure
- mocking strategy
- coroutine testing
- Flow assertions
Unchanged:
- production behavior
- architecture
- UI
This branch improved confidence. Not behavior.
Outcome
Tests are now:
- consistent
- readable
- deterministic
StreamBox is safer to evolve.
The architecture didn’t change. The trust did.
If you want to see it
Series Links
Previous: feature/ui-improvements — UX Design on home grid
Next: feature/snapshot-test — UI Testing with Paparazzi







