androidTest中的Android LiveData返回null

问题描述:

我正在运行androidTest工具测试,并且有一种方法可以使用Room从DAO对象返回LiveData.

I'm running an androidTest instrumentation test and I have a method that returns LiveData from a DAO object using Room.

我正在这样调用该方法:

I'm calling the method like so:

val animal = roomDatabase.animalsDao().getAnimal(1)
animal.observeForever(mMockObserver)
assertNotNull(animal.value)

我用Mockito模拟了观察者:

I used Mockito to mock the observer:

@Mock
private lateinit var mMockObserver = Observer<Animal>

这应该返回一个包含ID为1的Animal的LiveData实例,但它为null.据我了解,为了使LiveData返回任何内容,必须有一个观察者.我设置不正确吗?

This should return an instance of LiveData containing the Animal at id 1, but it's null. It's my understanding that in order for LiveData to return anything, there must be an observer. Did I set this up incorrectly?

注意:如果我在DAO中将getAnimal()的签名更改为直接返回Animal而不是LiveData,那么它就起作用了,所以我知道LiveData确实有用.

Note: If I change the signature of getAnimal() in the DAO to return an Animal directly, rather than a LiveData, then it works so I know it's something with LiveData.

进一步挖掘之后,我发现Google通过GitHub上的Architecture Components示例提供了一种实用程序方法.

After a little more digging I've found a utility method Google provided through their Architecture Components examples on GitHub.

LiveDataTestUtil

public class LiveDataTestUtil {

    /**
     * Get the value from a LiveData object. We're waiting for LiveData to emit, for 2 seconds.
     * Once we got a notification via onChanged, we stop observing.
     */
    public static <T> T getValue(final LiveData<T> liveData) throws InterruptedException {
        final Object[] data = new Object[1];
        final CountDownLatch latch = new CountDownLatch(1);
        Observer<T> observer = new Observer<T>() {
            @Override
            public void onChanged(@Nullable T o) {
                data[0] = o;
                latch.countDown();
                liveData.removeObserver(this);
            }
        };
        liveData.observeForever(observer);
        latch.await(2, TimeUnit.SECONDS);
        //noinspection unchecked
        return (T) data[0];
    }
}

这允许您传递LiveData实例并获取其持有的值.

This allows you to pass the LiveData instance and get back the value it holds.

更新(JUnit 4):

您还可以结合使用 InstantTaskExecutorRule 组合与 observeForever 来测试您的LiveData.在Kotlin中,在测试类的顶部设置@get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule()以确保LiveData被同步处理,然后在测试用例myLiveData.observeForever { /* Do something when event emitted */ }内部设置以获取LiveData值.

You can also use the InstantTaskExecutorRule combined with observeForever to test your LiveData. In Kotlin you set @get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule() at the top of your test class to ensure LiveData is handled synchronously, then inside your test cases myLiveData.observeForever { /* Do something when event emitted */ } to get the LiveData value.

更新(JUnit 5)

如果您使用的是JUnit5,则可以使用此扩展名代替上面的 Update(JUnit4)中解释的规则.

If you're using JUnit5, then you can use this extension instead of the Rule explained in Update (JUnit4) above.

class InstantTaskExecutorExtension : BeforeEachCallback, AfterEachCallback {

    override fun beforeEach(context: ExtensionContext?) {
        ArchTaskExecutor.getInstance().setDelegate(object : TaskExecutor() {
            override fun executeOnDiskIO(runnable: Runnable) {
                runnable.run()
            }

            override fun postToMainThread(runnable: Runnable) {
                runnable.run()
            }

            override fun isMainThread(): Boolean {
                return true
            }
        })
    }

    override fun afterEach(context: ExtensionContext?) {
        ArchTaskExecutor.getInstance().setDelegate(null)
    }
}

使用这种扩展方式来注释您的测试类,如下所示:

Use this extension by annotating your test class like so:

@ExtendWith(InstantTaskExecutorExtension::class)
class MyTestClass { ... }

如果您不熟悉扩展(可以替换JUnit 4规则),则可以在此处找到其他文档:

If you're new to extensions (they replace JUnit 4 Rules), you can find additional documentation here: https://junit.org/junit5/docs/current/user-guide/#extensions