Koin: declareMock() fails when using qualifiers on 2.0.0-rc-1

Created on 21 Mar 2019  路  8Comments  路  Source: InsertKoinIO/koin

Calling declareMock() using a qualifier fails with an error message similar to No definition found for 'ClassNameHere has been found. Check your module definitions.

It does work correctly when not using qualifiers. I believe it is failing because declareMock() doesn't pass the qualifier to the get() call at the end of the method.

Steps to reproduce

  1. Create a test similar to the following, replacing TestObject with any class you want
    @Test
    fun testWithQualifier() {
        val koin = koinApplication {
            modules(module {
                single(named("test")) { TestObject() }
            })
        }.koin
        koin.declareMock<TestObject>(named("test"))
    }

Expected behavior
Using declareMock() with a qualifier should work

Koin project used and used version (please complete the following information):
koin-testversion 2.0.0-rc-1

koin-test accepted issue

Most helpful comment

Hi!
This is a failing test case (skipped the imports),

class RepositoryTestRequestOk : KoinTest {

    private val permissionsRepository: DomainlayerContract.Datalayer.PermissionRepository<String, Boolean>
            by inject(named(name = PERMISSIONS_REPOSITORY_TAG))

    @Before
    fun setUp() {
        startKoin {
            modules(listOf(dataLayerModule))
        }
        val dummyParams = emptyList<String>()
        val okResponse = Either.Right(b = true)
        declareMock<DataLayerContract.PermissionsDataSource>(named(name = DataLayerContract.PERMISSIONS_DATA_SOURCE_TAG)) {
            given(checkIfPermissionGranted(permissionList = dummyParams)).willReturn(okResponse)
        }
    }

    @After
    fun tearDown() {
        stopKoin()
    }

    @Test
    fun `check that if data-source response is successful and true, a 'Right' value is returned`() {
        // given
        val dummyParams = emptyList<String>()
        // when
        val actualResult = permissionsRepository.requestPermission(permissionList = dummyParams)
        // then
        assertTrue((actualResult as? Either.Right) != null)
    }

}

and this is my Modules definition,

val dataLayerModule = module(override = true) {
    single<DomainlayerContract.Datalayer.PermissionRepository<String, Boolean>>(named(PERMISSIONS_REPOSITORY_TAG)) { Repository }
    factory<DataLayerContract.PermissionsDataSource>(named(PERMISSIONS_DATA_SOURCE_TAG)) { AndroidPermissionDataSource(androidContext()) }
}

Obviously, I am Unit Testing the Repository. To do that, I mock and stub the Data-Source which is invoked from the Repository.

I am always getting the "NoBeanDefined" error. However, if I declare the mock using Mockito and injecting it as a module to Koin (overriding, of course), it works!

Any idea? Thanks in advance

All 8 comments

fixed in rc-2 馃憤

Still failing on version 2.0.1

@ernestalmighty Looks like the test related to this case is green on master:
https://github.com/InsertKoinIO/koin/blob/1566605f8e8046f67579e414138e771dd5453624/koin-projects/koin-test/src/test/kotlin/org/koin/test/DeclareMockTests.kt#L88-L96

Are you sure you're using the latest version of Koin?
If this is still failing for you, can you open another issue?

Stil failing, I'm afraid,

declareMock<DataLayerContract.PermissionsDataSource>(named(PERMISSIONS_DATA_SOURCE_TAG))

Removing the qualifier from the Module makes the trick, but I do need the "name" qualifier :(

Would you be able to provide a failing test case or a project that I can checkout and eventually see what is going on?

Hi!
This is a failing test case (skipped the imports),

class RepositoryTestRequestOk : KoinTest {

    private val permissionsRepository: DomainlayerContract.Datalayer.PermissionRepository<String, Boolean>
            by inject(named(name = PERMISSIONS_REPOSITORY_TAG))

    @Before
    fun setUp() {
        startKoin {
            modules(listOf(dataLayerModule))
        }
        val dummyParams = emptyList<String>()
        val okResponse = Either.Right(b = true)
        declareMock<DataLayerContract.PermissionsDataSource>(named(name = DataLayerContract.PERMISSIONS_DATA_SOURCE_TAG)) {
            given(checkIfPermissionGranted(permissionList = dummyParams)).willReturn(okResponse)
        }
    }

    @After
    fun tearDown() {
        stopKoin()
    }

    @Test
    fun `check that if data-source response is successful and true, a 'Right' value is returned`() {
        // given
        val dummyParams = emptyList<String>()
        // when
        val actualResult = permissionsRepository.requestPermission(permissionList = dummyParams)
        // then
        assertTrue((actualResult as? Either.Right) != null)
    }

}

and this is my Modules definition,

val dataLayerModule = module(override = true) {
    single<DomainlayerContract.Datalayer.PermissionRepository<String, Boolean>>(named(PERMISSIONS_REPOSITORY_TAG)) { Repository }
    factory<DataLayerContract.PermissionsDataSource>(named(PERMISSIONS_DATA_SOURCE_TAG)) { AndroidPermissionDataSource(androidContext()) }
}

Obviously, I am Unit Testing the Repository. To do that, I mock and stub the Data-Source which is invoked from the Repository.

I am always getting the "NoBeanDefined" error. However, if I declare the mock using Mockito and injecting it as a module to Koin (overriding, of course), it works!

Any idea? Thanks in advance

Same scenario with @pablodeafsapps
Simplified test case with below.

class ItemsRepositoryImplTest : AutoCloseKoinTest() {

    val itemsLocalRepository by inject<ItemsRepository>(named("local"))
    val itemsRemoteRepository by inject<ItemsRepository>(named("remote"))

    @Mock
    lateinit var mockContext: Context

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        startKoin {
            androidContext(mockContext)
            modules(listOf(
                appModule
            )) }

        declareMock<ItemsRepository>(named("local"))
        declareMock<ItemsRepository>(named("remote"))
    }

    @Test
    fun test() {
        // fails
        // No definition found for 'com.example.testkoinapp.domain.ItemsRepository' has been found. Check your module definitions.
    }
}

This is my app module:

val appModule = module {
    single<ItemsRepository>(named("local")) {
        ItemsLocalRepository()
    }

    single<ItemsRepository>(named("remote")) {
        ItemsRemoteRepository()
    }
}

If no qualifier is defined, it will pass but any declaration of named qualifier always returns not found error.

It's still failing. Do have any solution?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

haroldadmin picture haroldadmin  路  3Comments

leodeleon22 picture leodeleon22  路  4Comments

CristianMG picture CristianMG  路  3Comments

dakuenjery picture dakuenjery  路  4Comments

pchmielowski picture pchmielowski  路  3Comments