One of my classes has a dependency of type Context. Before adding Koin to my project, I initialized this with a hard dependency on my Application class:
class ProfileRepository(
private var _context: Context? = null,
private var _profileRestService: IProfileRestService? = null
) : IProfileRepository {
init {
if (_context == null) {
_context = MyApplication.getInstance().applicationContext
}
}
Now, I want to use Koin to inject this dependency. This is how I've defined the module:
object AppModule {
@JvmField
val appModule = module {
single<IProfileRestService> { ProfileRestService() }
single<IProfileRepository> { ProfileRepository(androidContext(), get()) }
}
}
I'm starting Koin in the onCreate
method of my Application class (which is written in Java):
startKoin(singletonList(AppModule.appModule));
I want to test this class with an instrumented test and not a unit test because I want to use the real context and not a mock. This is my test:
@RunWith(AndroidJUnit4::class)
class MyTest : KoinTest {
private val _profileRepository by inject<IProfileRepository>()
@Test
fun testSomething() {
assertNotNull(_profileRepository)
}
The test is failing with an exception:
org.koin.error.BeanInstanceCreationException: Can't create definition for 'Single [name='IProfileRepository',class='com.my.app.data.profile.IProfileRepository']' due to error :
No compatible definition found. Check your module definition
I can get it to work with a unit test if I mock the context like so:
class MyTest : KoinTest {
private val _profileRepository by inject<IProfileRepository>()
@Before
fun before() {
startKoin(listOf(AppModule.appModule)) with mock(Context::class.java)
}
@After
fun after() {
stopKoin()
}
@Test
fun testSomething() {
assertNotNull(_profileRepository)
}
How can I make it work as an instrumented test with a real context?
Apparently there's no way to start Koin from a Java class and inject the application context. What that means is if one of your classes needs to get the context from the container, you must use org.koin.android.ext.android.startKoin
instead of org.koin.java.standalone.KoinJavaStarter.startKoin
.
Since my Application class is still written in Java, I created an object called KoinHelper with one method:
@JvmStatic
fun start(application: Application) {
application.startKoin(application, listOf(AppModule.appModule))
}
Then I called this from the onCreate
method of my Application class:
KoinHelper.start(this);
Now, the instrumented test I posted in my original answer runs just fine.
Please see this issue on GitHub for more info.