Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using Koin for android tests #119

Closed
AntoineJaury opened this issue May 4, 2018 · 6 comments
Closed

Using Koin for android tests #119

AntoineJaury opened this issue May 4, 2018 · 6 comments
Labels
android status:accepted accepted to be developed
Milestone

Comments

@AntoineJaury
Copy link

Searching for a solution to mock one of my repositories used as a Koin Module for instrumented tests, I finally found a way to mock it.

If you want to mock one of the Koin Modules for your instrumented test, you need to call the loadKoinModules method passing it a list of Koin Modules you want to override.

The problem here is that if the Koin Module you want override is already injected inside the components you want to test, then the loadKoinModules won't have any effect on these components. So you have to make sure the Koin Module is not injected in your components before mocking it.

A workaround I found is to override the ActivityTestRule you defined in your test class and to mock your Koin Module during the beforeActivityLaunchedof the ActivityTestRule.

This way, the Koin module will be mocked before activity is launched. As the module was injected once the Activity was created in my side, this solved the problem.

Here is my Test class including this solution:

@RunWith(AndroidJUnit4::class)
class LoginTest {

    val mockedUserRepository = Mockito.mock(UserDataSource::class.java)

    @Rule
    @JvmField
    val rule = object: ActivityTestRule<LoginActivity>(LoginActivity::class.java) {
        override fun beforeActivityLaunched() {
            super.beforeActivityLaunched()

            // This will replace the UserDataSource module previously defined 
            // in the Application class creation before the activity is launched
            // Otherwise ... components won't be reloaded
            val mockedUserModule = applicationContext {
                bean { mockedUserRepository as UserDataSource }
            }
            loadKoinModules(listOf(mockedUserModule))
        }
    }
   
   @Test
   fun loginWithUnactivatedAccount() {
        // Here the new module is loaded with all application components
        // and you can interact with the mockedUserRepository 
        ... 
   }
}

It would be great to have such example inside the documentation :)

@arnaudgiuliani arnaudgiuliani added this to the 1.0.0 milestone May 5, 2018
@arnaudgiuliani arnaudgiuliani added status:checking currently in analysis - discussion or need more detailed specs and removed status:accepted accepted to be developed labels May 12, 2018
@arnaudgiuliani arnaudgiuliani added status:accepted accepted to be developed and removed status:checking currently in analysis - discussion or need more detailed specs labels May 21, 2018
@patrice-conil
Copy link

Hi all,
I confirm that testing activity is a pain when we need to inject mock instances.
I think that an @MockBean annotation as in spring would be of great help.
In spring this annotation replaces the corresponding bean by the annotated mock.
This simplify greatly the test writing.
Patrice

@arnaudgiuliani
Copy link
Member

Hi @patrice-conil,

could be interesting to tell to Koin that we want mocks for given types 👍

@arnaudgiuliani
Copy link
Member

arnaudgiuliani commented Jun 19, 2018

In the snippet above, we can replace the snippet:

val mockedUserRepository = Mockito.mock(UserDataSource::class.java)

    @Rule
    @JvmField
    val rule = object: ActivityTestRule<LoginActivity>(LoginActivity::class.java) {
        override fun beforeActivityLaunched() {
            super.beforeActivityLaunched()

            // This will replace the UserDataSource module previously defined 
            // in the Application class creation before the activity is launched
            // Otherwise ... components won't be reloaded
            val mockedUserModule = applicationContext {
                bean { mockedUserRepository as UserDataSource }
            }
            loadKoinModules(listOf(mockedUserModule))
        }
    }

with:

 val rule = object: ActivityTestRule<LoginActivity>(LoginActivity::class.java) {
        override fun beforeActivityLaunched() {
            super.beforeActivityLaunched()

            // This will replace the UserDataSource module previously defined 
            // in the Application class creation before the activity is launched
           declareMock<UserDataSource>()
        }
    }

I've just added createMock() function in koin-test

@arnaudgiuliani
Copy link
Member

Check #151

@jerryOkafor
Copy link

Can not see the createMock() function in koin test

@arnaudgiuliani
Copy link
Member

Sorry, it's has been renamed declareMock (createMock was conflicting with other API).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
android status:accepted accepted to be developed
Projects
None yet
Development

No branches or pull requests

4 participants