简体   繁体   English

如何为 android 架构组件生命周期事件添加单元测试?

[英]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.

相关问题 如何测试 android 架构组件生命周期事件? - How can I test for android architecture components lifecycle events? Android架构组件GithubBrowserSample单元测试理解 - Android Architecture Components GithubBrowserSample unit test understanding 对话框上的 Android 生命周期事件 - Android life cycle event on dialog 我可以分别测试“活动”和“片段”的生命周期方法吗? - Can I test life cycle methods of Activities and Fragments separately? Android:单元测试:如何使用SensorManager创建单元测试? - Android: Unit Test: How can I create unit test with SensorManager? 一个重写的android生命周期方法如何在超级调用之后运行代码,而无需使用其后续的生命周期方法 - How an overrided android life cycle method can run the code after the super call without going to its succeeding life cycle method 我需要与Android应用生命周期保持一致 - I need assistence with android app life cycle 如何在 Android 中创建生命周期感知处理程序? - How to create Life Cycle Aware Handler in Android? Android生命周期哪个事件在生命周期中只触发一次? - Android life cycle which event fired only once during the life cycle? Android生命周期 - Android Life cycle
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM