I have been trying to get a simple Espresso
unit test work with Koin
as DI tool. Here are the dependencies that I am using in build.gradle
// testing with Koin
// because of this
// https://github.com/InsertKoinIO/koin/pull/604/commits/69391bc378bbb9007b9d82c46537e7d753be7ea3
androidTestImplementation 'org.mockito:mockito-android:3.1.0'
androidTestImplementation ("org.koin:koin-test:$koin_version") {
exclude group: 'org.mockito'
}
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
// stuff like ActivityTestRule
androidTestImplementation 'androidx.test:rules:1.2.0'
// AndroidJUnit4
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
// test runner
androidTestImplementation 'androidx.test:runner:1.2.0'
my ViewModel
declaration
open class LoginViewModel(private val apiService: MockApiService) : ViewModel() {
..
..
}
here is how its injected in Activity
private val loginViewModel: LoginViewModel by viewModel()
my custom TestRunner
in order to have custom TestApplication
instantiated
class MyTestRunner : AndroidJUnitRunner() {
override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application {
return super.newApplication(cl, TestApplication::class.java.name, context)
}
}
TestApplication
class. I have verified that this test class gets initialised when test is invoked
class TestApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidLogger()
androidContext(this@TestApplication)
modules(emptyList())
}
}
}
Here is my actual androidTest
. This fails as soon as activity is started with NoBeanDefFoundException
No definition found for 'com.abhishek.mvvmdemo.onboarding.LoginViewModel' has been found.
@RunWith(AndroidJUnit4::class)
@LargeTest
class LoginActivityTest : KoinTest {
private lateinit var loginViewModel: LoginViewModel
@get:Rule
val activityRule = ActivityTestRule(LoginActivity::class.java)
@Before
fun beforeTest() {
loginViewModel = declareMock()
loadKoinModules(
module {
// single { ApiModule.providesApiService() }
viewModel { loginViewModel }
}
)
}
@Test
fun testProgress() {
activityRule.launchActivity(null)
onView(withId(R.id.emailEt))
.perform(ViewActions.typeText("abhishek"))
}
@After
fun afterTest() {
stopKoin()
}
}
I have tried a lot of permutation and combinations but got no luck. I also happen to have following configuration in my gradle
testOptions {
animationsDisabled = true
}
packagingOptions {
pickFirst 'mockito-extensions/org.mockito.plugins.MockMaker'
}
and
testInstrumentationRunner "com.abhishek.mvvmdemo.MyTestRunner"
TL;DR
Here is a github sample that reproduces the issue