husi-testing

Guides writing Kotlin unit tests for the Husi composeApp using fakes, Koin, and coroutine test dispatchers.

1.8k|107|Updated Dec 24, 2023
One-click install
npx skills add https://github.com/xchacha20-poly1305/husi --skill husi-testing-xchacha20-poly1305
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: husi-testing
Source: https://github.com/xchacha20-poly1305/husi/tree/main/.agents/skills/husi-testing
Command: npx skills add https://github.com/xchacha20-poly1305/husi --skill husi-testing-xchacha20-poly1305

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? Writing tests for the Husi project requires knowing its specific conventions: hand-rolled fakes instead of mockk, Koin-aware base classes, and StandardTestDispatcher wiring. Without this guidance, tests hang, pollute each other through DataStore globals, or fail at runtime with Koin resolution errors. ## Core Features & Use Cases - Base class selection: Choose between MainDispatcherTest, HusiKoinTest, HusiKoinMainDispatcherTest, and HusiHttpKoinTest based on whether the code touches Koin singletons or coroutine dispatchers. - Fake-based testing: Use FakeRepository, FakeHttpClientFactory, and related fakes instead of mockk, with recorder-style assertions on lastRequest and lastResponse. - Testability refactoring: Introduce DI seams (interface, Koin binding, constructor injection, fake) when production code calls statics like Libcore.newHttpClient(). - Use Case: When adding a test for a ViewModel that resolves Repository and uses viewModelScope, extend HusiKoinMainDispatcherTest, run with runTest(dispatcher.scheduler), and collect SharedFlow events via backgroundScope.async before triggering the emit. ## Quick Start Ask the assistant to write a unit test for a specific ViewModel or updater class under composeApp following the husi-testing conventions.

Frequently Asked Questions about husi-testing

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I write a ViewModel unit test with kotlinx-coroutines runTest?

Extend HusiKoinMainDispatcherTest and wrap the test body in runTest(dispatcher.scheduler), passing the scheduler explicitly. Without it, the test dispatcher and viewModelScope run on different clocks and advanceUntilIdle becomes a no-op.

Should I use mockk or fakes for Kotlin unit testing?

This project prefers hand-rolled Fake classes implementing production interfaces over mockk. Fakes compile-check against real interfaces, reuse across tests, and avoid fragile mockkStatic calls against gobind classes on the desktop JVM.

Why does advanceUntilIdle do nothing in my coroutine test?

advanceUntilIdle only drains the test scheduler, so work resumed on a real dispatcher like Dispatchers.IO is invisible to it. Inject the dispatcher into the class under test or pass dispatcher.scheduler to runTest.

Why does viewModelOf throw NoDefinitionFoundException in Koin?

viewModelOf uses reflection and resolves every constructor parameter from Koin, ignoring Kotlin default values. Use an explicit factory like viewModel { FooViewModel(httpClientFactory = get()) } for ViewModels with defaulted params.

How do I test Kotlin code that collects SharedFlow events?

Start collecting with backgroundScope.async { flow.first() } before triggering the emit, because a SharedFlow with replay = 0 drops events emitted before collection begins. Then call advanceUntilIdle and assert on the awaited value.

Why do my DataStore tests fail with KoinApplicationException?

DataStore resolves its file path through resolveRepository(), which requires Koin to be initialized. Extend HusiKoinTest or HusiKoinMainDispatcherTest instead of MainDispatcherTest, and reset configurationStore in postStartKoin.