[英]How can I add unit test for android architecture components life cycle event?
I tried to add a unit test for my function which supports architecture components lifecycle event.我尝试为支持架构组件生命周期事件的 function 添加单元测试。 To support lifecycle event, I added the
@OnLifecycleEvent
annotation for my function which I want to do something when that event occurred.为了支持生命周期事件,我为我的 function 添加了
@OnLifecycleEvent
注释,我想在事件发生时做一些事情。
Everything is working as expected but I want to create a unit test for that function to check my function running when the intended event occurred.一切都按预期工作,但我想为 function 创建一个单元测试,以检查我的 function 在预期事件发生时运行。
public class CarServiceProvider implements LifecycleObserver {
public void bindToLifeCycle(LifecycleOwner lifecycleOwner) {
lifecycleOwner.getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onClear() {
Log.i("CarServiceProvider", "onClear called");
}
}
I tried to mock LifecycleOwner and create new LifecycleRegistery to change the state of lifecycle observer but I didn't do.我试图模拟 LifecycleOwner 并创建新的 LifecycleRegistery 来更改生命周期观察者的 state 但我没有这样做。
How can I test my onClear()
function called when state changed?当 state 更改时,如何测试我的
onClear()
function 调用?
You should be able to use the LifecycleRegistry您应该能够使用LifecycleRegistry
Your test would do something like below:您的测试将执行以下操作:
@Test
public void testSomething() {
LifecycleRegistry lifecycle = new LifecycleRegistry(mock(LifecycleOwner.class));
// Instantiate your class to test
CarServiceProvider carServiceProvider = new CarServiceProvider();
carServiceProvider.bindToLifeCycle(lifecycle);
// Set lifecycle state
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
// Verify that the ON_STOP event was handled, with an assert or similar check
...
}
If you are testing Lifecycle.Event.ON_DESTROY then you probably need to call handleLifecycleEvent(Lifecycle.Event.ON_CREATE) prior to this.如果您正在测试Lifecycle.Event.ON_DESTROY,那么您可能需要在此之前调用handleLifecycleEvent(Lifecycle.Event.ON_CREATE) 。
You can test using Unit tests without Roboletric as long as you mock the lifecycle owner properly.只要您正确模拟生命周期所有者,您就可以使用没有 Roboletric 的单元测试进行测试。
val lifecycleOwner: LifecycleOwner = Mockito.mock(LifecycleOwner::class.java)
val lifecycle = LifecycleRegistry(Mockito.mock(LifecycleOwner::class.java))
lifecycle.markState(Lifecycle.State.RESUMED)
Mockito.`when`(lifecycleOwner.lifecycle).thenReturn(lifecycle)
Use this lifecycleOwner when you observe a variable and you can use Mockito.verify to see if your callback has been called当您观察变量时使用此生命周期所有者,您可以使用 Mockito.verify 查看您的回调是否已被调用
Despite of I am not a big fan, I would go with Robolectric making use of ActivityController to achieve this.尽管我不是一个大粉丝,但我会和Robolectric 一起使用ActivityController来实现这一点。
Given the fact that the "Observables" of the Observer pattern applied in Android Lifecycle workflow are Activities, Fragments... An application context is a must and we need somehow bring it to our test scenario.鉴于在 Android Lifecycle 工作流中应用的Observer 模式的“Observables”是活动、片段......应用程序上下文是必须的,我们需要以某种方式将它带到我们的测试场景中。
I achieved the expected result by doing this我通过这样做达到了预期的结果
build.gradle构建.gradle
testCompile "org.robolectric:robolectric:3.5.1"
CarServiceProviderTest.java CarServiceProviderTest.java
@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class)
public class CarServiceProviderTest {
@Test
public void shouldFireOnClear(){
//Grab the Activity controller
ActivityController controller = Robolectric.buildActivity(JustTestActivity.class).create().start();
AppCompatActivity activity = (AppCompatActivity) controller.get();
//Instanciate our Observer
CarServiceProvider carServiceProvider = new CarServiceProvider();
carServiceProvider.bindToLifeCycle(activity);
//Fire the expected event
controller.stop();
//Assert
Assert.assertTrue(carServiceProvider.wasFired);
}
}
CarServiceProvider.java汽车服务提供者.java
public class CarServiceProvider implements LifecycleObserver {
public boolean wasFired;
public void bindToLifeCycle(LifecycleOwner lifecycleOwner) {
lifecycleOwner.getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onClear() {
wasFired = true;
}
}
Expanding on Raz's
answer, in Kotlin you can make an extension function to make this more reusable.扩展
Raz's
答案,在 Kotlin 中,您可以创建一个扩展函数以使其更可重用。
fun LifecycleObserver.testLifeCycleEvent(lifecycleEvent: Lifecycle.Event) {
val mockLifeCycleOwner: LifecycleOwner = mockk()
val lifecycleRegistry = LifecycleRegistry(mockLifeCycleOwner)
lifecycleRegistry.addObserver(this)
lifecycleRegistry.handleLifecycleEvent(lifecycleEvent)
}
In the original questioner's case, they have a fun bindToLifecycle()
.在最初的提问者的案例中,他们有一个
fun bindToLifecycle()
。 If you are doing something like that, you can just make an extension function for that as well so it applies to all LifecycleObserver
types:如果您正在做类似的事情,您也可以为此创建一个扩展函数,以便它适用于所有
LifecycleObserver
类型:
fun LifecycleObserver.bindToLifeCycle(lifecycle: Lifecycle) {
lifecycle.addObserver(this);
}
and then modify testLifeCycleEvent()
like this:然后像这样修改
testLifeCycleEvent()
:
fun LifecycleObserver.testLifeCycleEvent(lifecycleEvent: Lifecycle.Event) {
val mockLifeCycleOwner: LifecycleOwner = mockk()
val lifecycleRegistry = LifecycleRegistry(mockLifeCycleOwner)
this.bindLifecycle(lifecycleRegistry)
lifecycleRegistry.handleLifecycleEvent(lifecycleEvent)
}
If you want to test it with a real Unit test (not AndroidTest), your best bet is to use Robolectric, it mocks the Android framework and Robolectric 4.0 is coming out.如果你想用真正的单元测试(不是 AndroidTest)来测试它,你最好的选择是使用 Robolectric,它模拟了 Android 框架并且 Robolectric 4.0 即将推出。 However you're trying to test the actual interaction with the Android Framework, so that's a task better suited for a true integration testing suite and an AndroidTest.
但是,您正在尝试测试与 Android 框架的实际交互,因此该任务更适合真正的集成测试套件和 AndroidTest。 You can unit test it but the most sure way to test it would be to actually invoke the lifecycle event on a device (What Espresso would do) and verify it's called.
您可以对其进行单元测试,但最可靠的测试方法是在设备上实际调用生命周期事件(Espresso 会做什么)并验证它是否被调用。
There is a sample for Powermock v3.8 and RESUME event. Powermock v3.8 和 RESUME 事件有一个示例。 I use this event to show how to verify livedata value
我使用此事件来展示如何验证 livedata 值
#build.gradle #build.gradle
dependencies {
...
testImplementation 'org.robolectric:robolectric:3.8'
testImplementation "org.powermock:powermock-module-junit4:2.0.2"
testImplementation "org.powermock:powermock-module-junit4-rule:2.0.2"
testImplementation "org.powermock:powermock-api-mockito2:2.0.2"
testImplementation "org.powermock:powermock-classloading-xstream:1.6.4"
...
}
#CustomViewModel.kt #CustomViewModel.kt
class CustomViewModel() : ViewModel(), LifecycleObserver {
private val _outputData = MutableLiveData<Boolean>()
val outputData: LiveData<Boolean> = _outputData
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume() {
//TODO action
outputData.value = true
}
}
#CustomViewModelTest.kt #CustomViewModelTest.kt
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.mock
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.powermock.core.classloader.annotations.PowerMockIgnore
import org.powermock.modules.junit4.PowerMockRunner
import org.powermock.modules.junit4.PowerMockRunnerDelegate
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
@RunWith(PowerMockRunner::class)
@PowerMockRunnerDelegate(RobolectricTestRunner::class)
@PowerMockIgnore("org.mockito.*", "org.robolectric.*", "androidx.*")
@Config(manifest = Config.NONE)
class CustomViewModelTest {
@Mock
lateinit var observer: Observer<in Boolean>
@Before
fun beforeTest() {
MockitoAnnotations.initMocks(this)
}
@Test
@Config(sdk = [Build.VERSION_CODES.O])
fun `do an action on resume event`() {
val vm = spy(CustomViewModel())
vm.outputData.observeForever(observer)
vm.testLifecycleEvent(Lifecycle.Event.ON_RESUME)
verify(vm).onResume()
verify(observer).onChange(true)
}
}
fun LifecycleObserver.testLifecycleEvent(lifecycleEvent: Lifecycle.Event) {
val lifecycleOwner = Mockito.mock(LifecycleOwner::class.java)
val lifecycleRegistry = LifecycleRegistry(lifecycleOwner)
this.bindToLifecycle(lifecycleRegistry)
lifecycleRegistry.handleLifecycleEvent(lifecycleEvent)
}
fun LifecycleObserver.bindToLifecycle(lifecycle: Lifecycle) {
lifecycle.addObserver(this)
}
You can use the TestLifecycleOwner from the您可以使用 TestLifecycleOwner 从
androidx.lifecycle:lifecycle-runtime-testing
dependency依赖
https://developer.android.com/reference/kotlin/androidx/lifecycle/testing/TestLifecycleOwner https://developer.android.com/reference/kotlin/androidx/lifecycle/testing/TestLifecycleOwner
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.