Android 测试 Koin NoBeanDefFoundException
Android Test Koin NoBeanDefFoundException
我正在尝试使用 Koin 进行一些 Android 测试,但到目前为止,还没有成功。
我想用 Koin 注入的 ViewModel 测试基本 Activity。
我已经阅读了像 这样的帖子,但到目前为止我仍然有错误。
这是与测试配置相关的代码
没有模块的特定应用程序。
class MyTestApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin { emptyList<Module>() }
}
}
使用测试应用程序的特定 运行 用户
class OccazioTestRunner : AndroidJUnitRunner() {
override fun newApplication(
cl: ClassLoader?,
className: String?,
context: Context?
): Application {
return super.newApplication(cl, MyTestApplication::class.java.name, context)
}
}
在我的应用程序 build.gradle
中定义为 运行ner
android {
defaultConfig {
testInstrumentationRunner "fr.dsquad.occazio.occazio.OccazioTestRunner"
}
}
现在是我要测试的代码
在我的MyActivity
class MyActivity : AppCompatActivity(R.layout.activity_my) {
private val myViewModel by viewModel<MyViewModel>()
// Some code
}
和视图模型
class MyViewModel(private val useCase: MyUseCase): ViewModel() {
// Some code
}
最后,测试本身(在 androidTest 中)
@LargeTest
class MyActivityTest : KoinTest {
private lateinit var mockUseCase: MyUseCase
@JvmField
@Rule
val activityRule = activityScenarioRule<MyActivity>()
@Before
fun setup() {
mockUseCase = mock(MyUseCase::class.java)
startKoin {
modules(module { viewModel { MyViewModel(mockUseCase) } })
}
// I've also tried this
loadKoinModules(
module { viewModel { MyViewModel(mockUseCase) } }
)
}
@After
fun cleanUp() {
stopKoin()
}
@Test
fun someTest() = runBlocking {
// Mock the usecase response
`when`(mockUseCase.doSomething()).thenReturn("taratata")
// Start the scenario
val scenario = activityRule.scenario
// Verify we call the getUserId
// Activity is supposed to call the view model that will call the method doSomethingAdterThat.
verify(mockUseCase, times(1)).doSomethingAfterThat()
return@runBlocking
}
}
到目前为止,每次我 运行 这个代码都会出现这个错误
org.koin.core.error.NoBeanDefFoundException:
No definition found for 'mypackage.MyViewModel' has been found. Check your module definitions.
有趣的是,当
- 我将规则
activityScenarioRule
更改为已弃用的旧规则 ActivityTestRule(SplashScreenActivity::class.java, true, false)
- 我把
val scenario = activityRule.scenario
改成了val scenario = activityRule.launchActivity(null)
- 我在
setUp
中使用 loadKoinModules
而不是 startKoin
发生两件事
- 当我的测试单独开始时(通过 Android Studio):它通过了。
- 当我的测试与其他测试一起开始时(通过 class 或连接Android测试),只有一个通过,而旧的其他测试都被 KO。
其实我有两个问题。
- 如何使此测试与
activityScenarioRule
一起工作?
- 我怎样才能让它们“全部”工作(而不是一个接一个地启动它们来使它们工作)?
好的,不要问我它是如何工作的,但我想通了。
首先,因为我需要配置,所以我遵循了这个 https://medium.com/stepstone-tech/better-tests-with-androidxs-activityscenario-in-kotlin-part-1-6a6376b713ea .
我做了 3 件事
首先,我需要在启动前配置 koin,为此,我需要使用 ActivityScenario.launch()
和我之前定义的意图
private val intent = Intent(ApplicationProvider.getApplicationContext(), MyActivity::class.java)
var activityRule : ActivityScenario<MyActivity>? = null
// And then I can start my activity calling
activityRule = ActivityScenario.launch(intent)
然后“KoinApp 未启动”...我只是在 setUp
中用 startKoin
块替换了 loadKoinModules
块
startKoin { modules(module { viewModel { MyViewModel(mockUseCase) } }) }
最后,它对 1 个测试有效,但其他测试都失败了,因为没有调用 stopKoin()
之类的“KoinAppAlreadyStartedException”。 ..但是没有成功。
最后,我在 startKoin
之前放了一个 stopKoin()
,现在,一切都很顺利。
这是我的完整代码
@LargeTest
class MyActivityTest : KoinTest() {
private val intent = Intent(ApplicationProvider.getApplicationContext(), MyActivity::class.java)
var activityRule : ActivityScenario<MyActivity>? = null
private lateinit var mockUseCase: MyUseCase
@Before
fun setup() {
mockUseCase = mock(MyUseCase::class.java)
stopKoin()
startKoin {
modules(module { viewModel { MyViewModel(mockUseCase) } })
}
}
@After
fun cleanUp() {
activityRule?.close()
}
@Test
fun someTest() = runBlocking {
// Mock the usecase response
`when`(mockUseCase.doSomething()).thenReturn("taratata")
// Start the rule
val activityRule = ActivityScenario.launch(intent)
// Verify we call the getUserId
// Activity is supposed to call the view model that will call the method doSomethingAdterThat.
verify(mockUseCase, times(1)).doSomethingAfterThat()
return@runBlocking
}
}
呵呵,我也把这段代码添加到我的两个 Applications
override fun onTerminate() {
super.onTerminate()
stopKoin()
}
只是为了确定!
我正在尝试使用 Koin 进行一些 Android 测试,但到目前为止,还没有成功。
我想用 Koin 注入的 ViewModel 测试基本 Activity。
我已经阅读了像
这是与测试配置相关的代码
没有模块的特定应用程序。
class MyTestApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin { emptyList<Module>() }
}
}
使用测试应用程序的特定 运行 用户
class OccazioTestRunner : AndroidJUnitRunner() {
override fun newApplication(
cl: ClassLoader?,
className: String?,
context: Context?
): Application {
return super.newApplication(cl, MyTestApplication::class.java.name, context)
}
}
在我的应用程序 build.gradle
中定义为 运行ner
android {
defaultConfig {
testInstrumentationRunner "fr.dsquad.occazio.occazio.OccazioTestRunner"
}
}
现在是我要测试的代码
在我的MyActivity
class MyActivity : AppCompatActivity(R.layout.activity_my) {
private val myViewModel by viewModel<MyViewModel>()
// Some code
}
和视图模型
class MyViewModel(private val useCase: MyUseCase): ViewModel() {
// Some code
}
最后,测试本身(在 androidTest 中)
@LargeTest
class MyActivityTest : KoinTest {
private lateinit var mockUseCase: MyUseCase
@JvmField
@Rule
val activityRule = activityScenarioRule<MyActivity>()
@Before
fun setup() {
mockUseCase = mock(MyUseCase::class.java)
startKoin {
modules(module { viewModel { MyViewModel(mockUseCase) } })
}
// I've also tried this
loadKoinModules(
module { viewModel { MyViewModel(mockUseCase) } }
)
}
@After
fun cleanUp() {
stopKoin()
}
@Test
fun someTest() = runBlocking {
// Mock the usecase response
`when`(mockUseCase.doSomething()).thenReturn("taratata")
// Start the scenario
val scenario = activityRule.scenario
// Verify we call the getUserId
// Activity is supposed to call the view model that will call the method doSomethingAdterThat.
verify(mockUseCase, times(1)).doSomethingAfterThat()
return@runBlocking
}
}
到目前为止,每次我 运行 这个代码都会出现这个错误
org.koin.core.error.NoBeanDefFoundException:
No definition found for 'mypackage.MyViewModel' has been found. Check your module definitions.
有趣的是,当
- 我将规则
activityScenarioRule
更改为已弃用的旧规则ActivityTestRule(SplashScreenActivity::class.java, true, false)
- 我把
val scenario = activityRule.scenario
改成了val scenario = activityRule.launchActivity(null)
- 我在
setUp
中使用
loadKoinModules
而不是 startKoin
发生两件事
- 当我的测试单独开始时(通过 Android Studio):它通过了。
- 当我的测试与其他测试一起开始时(通过 class 或连接Android测试),只有一个通过,而旧的其他测试都被 KO。
其实我有两个问题。
- 如何使此测试与
activityScenarioRule
一起工作? - 我怎样才能让它们“全部”工作(而不是一个接一个地启动它们来使它们工作)?
好的,不要问我它是如何工作的,但我想通了。
首先,因为我需要配置,所以我遵循了这个 https://medium.com/stepstone-tech/better-tests-with-androidxs-activityscenario-in-kotlin-part-1-6a6376b713ea .
我做了 3 件事
首先,我需要在启动前配置 koin,为此,我需要使用 ActivityScenario.launch()
和我之前定义的意图
private val intent = Intent(ApplicationProvider.getApplicationContext(), MyActivity::class.java)
var activityRule : ActivityScenario<MyActivity>? = null
// And then I can start my activity calling
activityRule = ActivityScenario.launch(intent)
然后“KoinApp 未启动”...我只是在 setUp
中用startKoin
块替换了 loadKoinModules
块
startKoin { modules(module { viewModel { MyViewModel(mockUseCase) } }) }
最后,它对 1 个测试有效,但其他测试都失败了,因为没有调用 stopKoin()
之类的“KoinAppAlreadyStartedException”。 startKoin
之前放了一个 stopKoin()
,现在,一切都很顺利。
这是我的完整代码
@LargeTest
class MyActivityTest : KoinTest() {
private val intent = Intent(ApplicationProvider.getApplicationContext(), MyActivity::class.java)
var activityRule : ActivityScenario<MyActivity>? = null
private lateinit var mockUseCase: MyUseCase
@Before
fun setup() {
mockUseCase = mock(MyUseCase::class.java)
stopKoin()
startKoin {
modules(module { viewModel { MyViewModel(mockUseCase) } })
}
}
@After
fun cleanUp() {
activityRule?.close()
}
@Test
fun someTest() = runBlocking {
// Mock the usecase response
`when`(mockUseCase.doSomething()).thenReturn("taratata")
// Start the rule
val activityRule = ActivityScenario.launch(intent)
// Verify we call the getUserId
// Activity is supposed to call the view model that will call the method doSomethingAdterThat.
verify(mockUseCase, times(1)).doSomethingAfterThat()
return@runBlocking
}
}
呵呵,我也把这段代码添加到我的两个 Applications
override fun onTerminate() {
super.onTerminate()
stopKoin()
}
只是为了确定!