docs/reference/koin-test/verify.md
Koin allows you to verify your configuration modules, avoiding discovering dependency injection issues at runtime.
:::info Future: Compile-Time Safety
Both verify() and checkModules() APIs will be replaced by native compile-time safety in the Koin Compiler Plugin. This will validate your entire configuration at build time, catching errors before runtime.
See Koin Compiler Plugin for more information. :::
Use the verify() extension function on a Koin Module. Under the hood, this will verify all constructor classes and crosscheck with the Koin configuration to know if there is a component declared for this dependency. In case of failure, the function will throw a MissingKoinDefinitionException.
val niaAppModule = module {
includes(
jankStatsKoinModule,
dataKoinModule,
syncWorkerKoinModule,
topicKoinModule,
authorKoinModule,
interestsKoinModule,
settingsKoinModule,
bookMarksKoinModule,
forYouKoinModule
)
viewModel<MainActivityViewModel>()
}
class NiaAppModuleCheck {
@Test
fun checkKoinModule() {
// Verify Koin configuration
niaAppModule.verify()
}
}
Launch the JUnit test and you're done!
The verify() API is ultra light to run and doesn't require any kind of mock/stub to run on your configuration.
When you have a configuration that implies injected objects with parametersOf, the verification will fail because there is no definition of the parameter's type in your configuration.
However you can define a parameter type, to be injected with given definition definition<Type>(Class1::class, Class2::class ...).
class ModuleCheck {
// given a definition with an injected definition
val module = module {
single { (a: Simple.ComponentA) -> Simple.ComponentB(a) }
}
@Test
fun checkKoinModule() {
// Verify and declare Injected Parameters
module.verify(
injections = injectedParameters(
definition<Simple.ComponentB>(Simple.ComponentA::class)
)
)
}
}
We can add types as "white-listed". This means that this type is considered as present in the system for any definition:
class NiaAppModuleCheck {
@Test
fun checkKoinModule() {
// Verify Koin configuration
niaAppModule.verify(
// List types used in definitions but not declared directly (like parameter injection)
extraTypes = listOf(MyType::class ...)
)
}
}
Annotations from koin-core-annotations help Koin infer injection contracts and validate configurations. Instead of having a complex DSL configuration, this helps identify those elements:
// indicates that "a" is an injected parameter
class ComponentB(@InjectedParam val a: ComponentA)
// indicates that "a" is dynamically provided
class ComponentBProvided(@Provided val a: ComponentA)
This helps prevent subtle issues during testing or runtime without writing custom verification logic.
:::warning
The checkModules() API is deprecated since Koin 4.0. Use verify() instead, or migrate to the Koin Compiler Plugin for compile-time safety.
:::
The checkModules() function launches your modules and tries to run each possible definition.
class CheckModulesTest : KoinTest {
@Test
fun verifyKoinApp() {
koinApplication {
modules(module1, module2)
checkModules()
}
}
}
Or using checkKoinModules:
class CheckModulesTest : KoinTest {
@Test
fun verifyKoinApp() {
checkKoinModules(listOf(module1, module2))
}
}
For any definition using injected parameters, properties or dynamic instances:
withInstance(value) - will add value instance to Koin graphwithInstance<MyType>() - will add a mocked instance of MyType (requires MockProviderRule)withParameter<Type>(qualifier){ qualifier -> value } - will add value instance to be injected as parameterwithProperty(key, value) - add property to KoinTo use mocks with checkModules, provide a MockProviderRule:
@get:Rule
val mockProvider = MockProviderRule.create { clazz ->
// Mock with your framework here given clazz
Mockito.mock(clazz.java)
}
val myModule = module {
factory { (id: String) -> FactoryPresenter(id) }
}
Verify with:
class CheckModulesTest : KoinTest {
@Test
fun verifyKoinApp() {
koinApplication {
modules(myModule)
checkModules(){
// value to add to Koin, used by definition
withInstance("_my_id_value")
}
}
}
}
class CheckModulesTest {
@get:Rule
val rule: TestRule = InstantTaskExecutorRule()
@get:Rule
val mockProvider = MockProviderRule.create { clazz ->
Mockito.mock(clazz.java)
}
@Test
fun `test DI modules`(){
checkKoinModules(allModules) {
withInstance<Context>()
withInstance<Application>()
withInstance<SavedStateHandle>()
withInstance<WorkerParameters>()
}
}
}
Link scopes using withScopeLink:
val myModule = module {
scope(named("scope1")) {
scoped { ComponentA() }
}
scope(named("scope2")) {
scoped { ComponentB(get()) }
}
}
@Test
fun `test DI modules`(){
koinApplication {
modules(myModule)
checkModules(){
withScopeLink(named("scope2"), named("scope1"))
}
}
}
Both verification APIs will be replaced by the Koin Compiler Plugin's compile-time safety feature:
| Current | Future |
|---|---|
module.verify() | Compiler Plugin (automatic) |
checkModules() | Compiler Plugin (automatic) |
| Runtime verification | Compile-time verification |
| Manual test setup | No test code needed |
When the Compiler Plugin compile-time safety is available, you'll get dependency validation at build time without writing any verification tests.
See Compiler Plugin Setup for setup instructions.