Android androidTest 中的 LiveData returns 空
Android LiveData in androidTest returns null
我是 运行 androidTest 仪器测试,我有一个方法可以使用 Room returns 来自 DAO 对象的 LiveData。
我是这样调用方法的:
val animal = roomDatabase.animalsDao().getAnimal(1)
animal.observeForever(mMockObserver)
assertNotNull(animal.value)
我用 Mockito 来模拟观察者:
@Mock
private lateinit var mMockObserver = Observer<Animal>
这应该 return 包含 ID 为 1 的动物的 LiveData 实例,但它为空。据我了解,为了让 LiveData return 任何东西,必须有一个观察者。我是不是设置错了?
注意:如果我将 DAO 中的 getAnimal() 的签名直接更改为 return 动物,而不是 LiveData,那么它会起作用,所以我知道它与 LiveData 有关。
经过更多挖掘后,我发现了一个实用方法 Google,通过他们在 GitHub 上的架构组件示例提供。
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 实例并取回它持有的值。
更新(JUnit 4):
您还可以使用 InstantTaskExecutorRule combined with observeForever 来测试您的 LiveData。在 Kotlin 中,您在测试 class 的顶部设置 @get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule()
以确保同步处理 LiveData,然后在您的测试用例中 myLiveData.observeForever { /* Do something when event emitted */ }
获取 LiveData 值。
更新 (JUnit 5)
如果您使用的是 JUnit5,则可以使用此扩展来代替上述 更新 (JUnit4) 中解释的规则。
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)
}
}
通过像这样注释您的测试 class 使用此扩展:
@ExtendWith(InstantTaskExecutorExtension::class)
class MyTestClass { ... }
如果您不熟悉扩展(它们取代了 JUnit 4 规则),您可以在此处找到其他文档:https://junit.org/junit5/docs/current/user-guide/#extensions
如果你正在做 Kotlin,而不是 Java,那么你也可以使用:
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
// Original Java: https://github.com/googlesamples/android-architecture-components/blob/master/BasicSample/app/src/androidTest/java/com/example/android/persistence/LiveDataTestUtil.java
object 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.
*/
@Throws(InterruptedException::class)
fun <T> getValue(liveData: LiveData<T>): T? {
val data = arrayOfNulls<Any>(1)
val latch = CountDownLatch(1)
val observer: Observer<T?> = object : Observer<T?> {
override fun onChanged(o: T?) {
data[0] = o
latch.countDown()
liveData.removeObserver(this)
}
}
liveData.observeForever(observer)
latch.await(2, TimeUnit.SECONDS)
@Suppress("UNCHECKED_CAST")
return data[0] as T?
}
}
(目前 A/S 将 Java 自动迁移到 Kotlin 的功能对于 Google class 不能正常工作)
我是 运行 androidTest 仪器测试,我有一个方法可以使用 Room returns 来自 DAO 对象的 LiveData。
我是这样调用方法的:
val animal = roomDatabase.animalsDao().getAnimal(1)
animal.observeForever(mMockObserver)
assertNotNull(animal.value)
我用 Mockito 来模拟观察者:
@Mock
private lateinit var mMockObserver = Observer<Animal>
这应该 return 包含 ID 为 1 的动物的 LiveData 实例,但它为空。据我了解,为了让 LiveData return 任何东西,必须有一个观察者。我是不是设置错了?
注意:如果我将 DAO 中的 getAnimal() 的签名直接更改为 return 动物,而不是 LiveData,那么它会起作用,所以我知道它与 LiveData 有关。
经过更多挖掘后,我发现了一个实用方法 Google,通过他们在 GitHub 上的架构组件示例提供。
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 实例并取回它持有的值。
更新(JUnit 4):
您还可以使用 InstantTaskExecutorRule combined with observeForever 来测试您的 LiveData。在 Kotlin 中,您在测试 class 的顶部设置 @get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule()
以确保同步处理 LiveData,然后在您的测试用例中 myLiveData.observeForever { /* Do something when event emitted */ }
获取 LiveData 值。
更新 (JUnit 5)
如果您使用的是 JUnit5,则可以使用此扩展来代替上述 更新 (JUnit4) 中解释的规则。
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)
}
}
通过像这样注释您的测试 class 使用此扩展:
@ExtendWith(InstantTaskExecutorExtension::class)
class MyTestClass { ... }
如果您不熟悉扩展(它们取代了 JUnit 4 规则),您可以在此处找到其他文档:https://junit.org/junit5/docs/current/user-guide/#extensions
如果你正在做 Kotlin,而不是 Java,那么你也可以使用:
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
// Original Java: https://github.com/googlesamples/android-architecture-components/blob/master/BasicSample/app/src/androidTest/java/com/example/android/persistence/LiveDataTestUtil.java
object 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.
*/
@Throws(InterruptedException::class)
fun <T> getValue(liveData: LiveData<T>): T? {
val data = arrayOfNulls<Any>(1)
val latch = CountDownLatch(1)
val observer: Observer<T?> = object : Observer<T?> {
override fun onChanged(o: T?) {
data[0] = o
latch.countDown()
liveData.removeObserver(this)
}
}
liveData.observeForever(observer)
latch.await(2, TimeUnit.SECONDS)
@Suppress("UNCHECKED_CAST")
return data[0] as T?
}
}
(目前 A/S 将 Java 自动迁移到 Kotlin 的功能对于 Google class 不能正常工作)