Skip to content

test: set the test Main dispatcher before every spec callback - #256

Merged
Lemkinator merged 3 commits into
mainfrom
test/main-dispatcher-extension
Sep 29, 2026
Merged

Lemkinator merged 3 commits into
mainfrom
test/main-dispatcher-extension

Conversation

@Lemkinator

@Lemkinator Lemkinator commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Replaces TestDispatcherListener with MainDispatcherExtension, a project TestCaseExtension registered in ProjectConfig. Kotest 6.2.5 runs a spec's beforeContainer/beforeEach callbacks before a project listener's beforeTest. The old listener therefore set Dispatchers.Main too late.
  • A ViewModel built in beforeEach found no Main when it touched viewModelScope. Lifecycle then falls back to Dispatchers.Default, so its launches raced the test. SettingsViewModelTest's ViewModel now runs on the test thread instead of DefaultDispatcher-worker-2, with no spec edit.
  • The extension sets Main before a top-level test's callbacks and resets it after that test. Nested tests and after-callbacks keep Main.
  • AboutViewModelTest, AppPickerViewModelTest, SwitchBarViewModelTest and OOBEViewModelTest drop their own setMain/resetMain.
  • OOBEViewModelTest names the Main scheduler it advances and builds it in beforeEach. A dispatcher built in the spec body gets its own scheduler, so the ViewModel's delay never advances and the test times out.

Behavior changes

None in app code. This PR changes test infrastructure only.

Coverage

  • MainDispatcherExtensionTest covers beforeEach, beforeContainer, afterContainer, a nested test, and a Main installed in a container body. Its afterSpec asserts that Main is reset.
  • The test fails on the old listener.
  • Kover stays at 100/100.

Verification

  • spotlessCheck detekt lintDebug testDebugUnitTest koverVerifyDebug verifyRoborazziDebug: PASS, 535 tests.
  • Full suite: 3 runs green.
  • Parity: EXACT, drift 0.

Notes

  • Spec-body initializers, beforeSpec and afterSpec run outside any TestCaseExtension. The extension KDoc states this limit.
  • Commits:
    • 38b5371 test: set the test Main dispatcher before spec callbacks
    • 5604a93 test: rely on the project Main dispatcher in ViewModel specs
    • 987389f test: name the Main scheduler in the OOBE spec

🤖 Generated with Claude Code

https://claude.ai/code/session_01UXgoU8egK3DzNLho2znqJz

Replace TestDispatcherListener with a project-wide MainDispatcherExtension that sets Dispatchers.Main for root tests and resets it after execution. Add lifecycle and nested-test coverage. Remove redundant per-test Main dispatcher setup from four ViewModel test suites.

Kotest runs spec beforeEach and beforeContainer callbacks before a
BeforeTestListener, so a ViewModel built there found no Main and its
viewModelScope fell back to Dispatchers.Default. A TestCaseExtension wraps
every callback of a top-level test; it resets Main only after that test, so
nested tests and after-callbacks still see the dispatcher.
MainDispatcherExtension now sets Main before beforeEach, so the specs drop
their own setMain and resetMain. The OOBE spec builds its dispatcher in
beforeEach: a TestDispatcher created there shares the scheduler of the test
Main, while one created in the spec body gets its own scheduler and no
longer advances the ViewModel's delay.
The spec holds the scheduler of the test Main dispatcher, taken in
beforeEach, and advances it directly, so the dependency on Main's
scheduler shows in the code.
@coderabbitai

coderabbitai Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 61d51993-958b-4760-9ab6-3bcb26b0c83b

📥 Commits

Reviewing files that changed from the base of the PR and between c5228ec and 987389f.

📒 Files selected for processing (7)
  • app/src/test/java/de/lemke/oneuisample/MainDispatcherExtension.kt
  • app/src/test/java/de/lemke/oneuisample/MainDispatcherExtensionTest.kt
  • app/src/test/java/de/lemke/oneuisample/ui/AboutViewModelTest.kt
  • app/src/test/java/de/lemke/oneuisample/ui/AppPickerViewModelTest.kt
  • app/src/test/java/de/lemke/oneuisample/ui/OOBEViewModelTest.kt
  • app/src/test/java/de/lemke/oneuisample/ui/SwitchBarViewModelTest.kt
  • app/src/test/java/io/kotest/provided/ProjectConfig.kt
💤 Files with no reviewable changes (3)
  • app/src/test/java/de/lemke/oneuisample/ui/AppPickerViewModelTest.kt
  • app/src/test/java/de/lemke/oneuisample/ui/SwitchBarViewModelTest.kt
  • app/src/test/java/de/lemke/oneuisample/ui/AboutViewModelTest.kt

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The test suite replaces its per-test Main dispatcher listener with a Kotest test-case extension. New tests cover dispatcher behavior across test lifecycles, and ViewModel tests remove local Main dispatcher setup.

Changes

Main dispatcher test setup

Layer / File(s) Summary
Add and register the dispatcher extension
app/src/test/java/de/lemke/oneuisample/MainDispatcherExtension.kt, app/src/test/java/io/kotest/provided/ProjectConfig.kt, app/src/test/java/de/lemke/oneuisample/MainDispatcherExtensionTest.kt
A TestCaseExtension installs an UnconfinedTestDispatcher for root tests and resets Main afterward. ProjectConfig registers the extension. New tests check dispatcher behavior across test and container lifecycles.
Update ViewModel test dispatcher setup
app/src/test/java/de/lemke/oneuisample/ui/AboutViewModelTest.kt, app/src/test/java/de/lemke/oneuisample/ui/AppPickerViewModelTest.kt, app/src/test/java/de/lemke/oneuisample/ui/OOBEViewModelTest.kt, app/src/test/java/de/lemke/oneuisample/ui/SwitchBarViewModelTest.kt
ViewModel tests remove per-test Main replacement and reset. The OOBE navigation test advances a stored TestCoroutineScheduler.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Other

Merge Risk: ⚪ Minimal · up to 98738

The shared dispatcher setup covers nested ViewModel tests, with no identified issue requiring a fix before merge.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 98738

The change is confined to test infrastructure, and no new application attack path was identified. The remaining risk is that overlapping tests could interfere with each other’s dispatcher state; whether such overlap occurs is not established.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — Any dispatcher-isolation failure identified here would affect JVM test execution rather than directly grant an application privilege or expose a deployed service.

Trust Boundaries and Controls

  • observed — The regression test expects Main during test callbacks and expects it to be unavailable in afterSpec; the extension does not promise Main for the spec lifecycle outside intercepted test cases.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: configuring the test Main dispatcher before spec callbacks. It is concise and directly related to the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit checks the dispatcher’s pace,
Then hops through each test-case place.
Main returns when root tests end,
A scheduler helps events ascend.
The burrow’s tests now run in line.

Comment @coderabbitai help to get the list of available commands.

@mergestorm-vortex

Copy link
Copy Markdown

Plan limit reached

You've used all Starter plan credits for this billing period (70 limit), so this pull request was not reviewed (987389f).

Upgrade to a higher plan or wait until your next billing period: See plans on the billing page

@greptile-apps

greptile-apps Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Low risk] Test infrastructure refactors dispatcher setup.

The PR appears safe to merge; no actionable regression was identified.

Summary

The PR moves test Main-dispatcher setup from a listener to a root-test extension, removes redundant ViewModel-spec setup, and adds lifecycle coverage.

  • The OOBE test now captures the Main scheduler during beforeEach for its delayed-event assertion.

Reviews (1) · Last reviewed commit: "test: name the Main scheduler in the OOB..."

@codecov

codecov Bot commented Sep 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@Lemkinator
Lemkinator merged commit 10b692d into main Sep 29, 2026
10 checks passed
@Lemkinator
Lemkinator deleted the test/main-dispatcher-extension branch September 29, 2026 16:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant