簡體   English   中英

如何為 android 架構組件生命周期事件添加單元測試?

[英]How can I add unit test for android architecture components life cycle event?

我嘗試為支持架構組件生命周期事件的 function 添加單元測試。 為了支持生命周期事件,我為我的 function 添加了@OnLifecycleEvent注釋,我想在事件發生時做一些事情。

一切都按預期工作,但我想為 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");
    }
 }

我試圖模擬 LifecycleOwner 並創建新的 LifecycleRegistery 來更改生命周期觀察者的 state 但我沒有這樣做。

當 state 更改時,如何測試我的onClear() function 調用?

您應該能夠使用LifecycleRegistry

您的測試將執行以下操作:

@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
  ...
}

如果您正在測試Lifecycle.Event.ON_DESTROY,那么您可能需要在此之前調用handleLifecycleEvent(Lifecycle.Event.ON_CREATE)

只要您正確模擬生命周期所有者,您就可以使用沒有 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)

當您觀察變量時使用此生命周期所有者,您可以使用 Mockito.verify 查看您的回調是否已被調用

盡管我不是一個大粉絲,但我會和Robolectric 一起使用ActivityController來實現這一點。

鑒於在 Android Lifecycle 工作流中應用的Observer 模式的“Observables”是活動、片段......應用程序上下文是必須的,我們需要以某種方式將它帶到我們的測試場景中。

我通過這樣做達到了預期的結果

構建.gradle

testCompile "org.robolectric:robolectric:3.5.1"

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);
    }
}

汽車服務提供者.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;
    }
}

擴展Raz's答案,在 Kotlin 中,您可以創建一個擴展函數以使其更可重用。

fun LifecycleObserver.testLifeCycleEvent(lifecycleEvent: Lifecycle.Event) {
   val mockLifeCycleOwner: LifecycleOwner = mockk()
   val lifecycleRegistry = LifecycleRegistry(mockLifeCycleOwner)
   lifecycleRegistry.addObserver(this)
   lifecycleRegistry.handleLifecycleEvent(lifecycleEvent)
}

在最初的提問者的案例中,他們有一個fun bindToLifecycle() 如果您正在做類似的事情,您也可以為此創建一個擴展函數,以便它適用於所有LifecycleObserver類型:

fun LifecycleObserver.bindToLifeCycle(lifecycle: Lifecycle) {
        lifecycle.addObserver(this);
    }

然后像這樣修改testLifeCycleEvent()

fun LifecycleObserver.testLifeCycleEvent(lifecycleEvent: Lifecycle.Event) {
   val mockLifeCycleOwner: LifecycleOwner = mockk()
   val lifecycleRegistry = LifecycleRegistry(mockLifeCycleOwner)
   this.bindLifecycle(lifecycleRegistry)
   lifecycleRegistry.handleLifecycleEvent(lifecycleEvent)
}

如果你想用真正的單元測試(不是 AndroidTest)來測試它,你最好的選擇是使用 Robolectric,它模擬了 Android 框架並且 Robolectric 4.0 即將推出。 但是,您正在嘗試測試與 Android 框架的實際交互,因此該任務更適合真正的集成測試套件和 AndroidTest。 您可以對其進行單元測試,但最可靠的測試方法是在設備上實際調用生命周期事件(Espresso 會做什么)並驗證它是否被調用。

Powermock v3.8 和 RESUME 事件有一個示例。 我使用此事件來展示如何驗證 livedata 值

#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

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

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)
}

您可以使用 TestLifecycleOwner 從

androidx.lifecycle:lifecycle-runtime-testing

依賴

https://developer.android.com/reference/kotlin/androidx/lifecycle/testing/TestLifecycleOwner

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM