问题描述
我目前正在使用新的 Android体系结构组件.具体来说,我正在实现一个Room数据库,该数据库在其中一个查询中返回一个LiveData
对象.插入和查询工作正常,但是使用单元测试测试查询方法时出现问题.
I'm currently developing an app using the newly Android Architecture Components. Specifically I'm implementing a Room Database that returns a LiveData
object on one of it's queries. Insertion and querying works as expected, however I have an issue testing the query method using unit test.
这是我要测试的DAO:
Here is the DAO I'm trying to test:
NotificationDao.kt
@Dao
interface NotificationDao {
@Insert
fun insertNotifications(vararg notifications: Notification): List<Long>
@Query("SELECT * FROM notifications")
fun getNotifications(): LiveData<List<Notification>>
}
您可以看到,查询函数返回一个LiveData
对象,如果我将其更改为一个List
,Cursor
或基本上任何其他内容,那么我会得到预期的结果,即插入到数据库.
As you can tell, the query function returns a LiveData
object, if I change this to be just a List
, Cursor
or basically whatever then I get the expected result, which is the data inserted in the Database.
问题在于以下测试将始终失败,因为LiveData
对象的value
始终为null
:
The issue is that the following test will always fail because the value
of the LiveData
object is always null
:
NotificationDaoTest.kt
lateinit var db: SosafeDatabase
lateinit var notificationDao: NotificationDao
@Before
fun setUp() {
val context = InstrumentationRegistry.getTargetContext()
db = Room.inMemoryDatabaseBuilder(context, SosafeDatabase::class.java).build()
notificationDao = db.notificationDao()
}
@After
@Throws(IOException::class)
fun tearDown() {
db.close()
}
@Test
fun getNotifications_IfNotificationsInserted_ReturnsAListOfNotifications() {
val NUMBER_OF_NOTIFICATIONS = 5
val notifications = Array(NUMBER_OF_NOTIFICATIONS, { i -> createTestNotification(i) })
notificationDao.insertNotifications(*notifications)
val liveData = notificationDao.getNotifications()
val queriedNotifications = liveData.value
if (queriedNotifications != null) {
assertEquals(queriedNotifications.size, NUMBER_OF_NOTIFICATIONS)
} else {
fail()
}
}
private fun createTestNotification(id: Int): Notification {
//method omitted for brevity
}
所以问题是:有人知道更好的方法来执行涉及LiveData对象的单元测试吗?
推荐答案
当有观察者时,房间会懒惰地计算LiveData
的值.
Room calculates the LiveData
's value lazily when there is an observer.
您可以检查示例应用.
它使用 getValue 实用程序方法,该方法添加了一个观察者以获取值:
It uses a getValue utility method which adds an observer to get the value:
public static <T> T getOrAwaitValue(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];
}
最好使用kotlin,您可以将其设为扩展功能:).
Better w/ kotlin, you can make it an extensions function :).
这篇关于单元测试室和LiveData的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!