尽管Realm被模拟,但实际的close()方法被调用

时间:2018-04-05 08:17:23

标签: android unit-testing kotlin realm mockito

在调用保存save()之后,我有一个相当简单的RealmModel方法来保留realm.close(),因为不再需要数据库。

问题:虽然Realm是使用mockito进行模拟的,但实际调用了close()方法。这会导致异常:

  

IllegalStateException:从错误的线程访问Realm。   Realm实例只能在创建它的线程上关闭。

mockito无法模仿Realm?我不想仅仅为了测试这个案例而包含PowerMock:D

使用realm-gradle-plugin 5.0.0

进行测试

测试类

import io.realm.Realm
import io.realm.RealmModel

class TestedClass {

    fun save(realm: Realm, objectToBeSaved: RealmModel) {
        // Persist your data in a transaction
        realm.executeTransaction {
            // Using executeTransaction with a lambda reduces code size
            // and makes it impossible to forget to commit the transaction.
            it.copyToRealm(objectToBeSaved)
        }
        // Close database after saving (this causes the exception)
        realm.close()
    }
}

单元测试

import com.nhaarman.mockito_kotlin.any
import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.verify

@Test
fun save() {
    val testedClass = TestedClass()
    val mockRealm: Realm = mock()
    val objectToBeSaved: RealmModel = mock()

    testedClass.save(mockRealm, objectToBeSaved) // this causes the exception

    verify(mockRealm).executeTransaction(any())
    verify(mockRealm).copyToRealm(objectToBeSaved)
    verify(mockRealm).close()
}

2 个答案:

答案 0 :(得分:1)

解决方案是新的Realm版本。

似乎在realm-gradle-plugin 5.0.0 5.3.1 之间的某个问题已在Realm库方面得到解决,即使我无法在changelog上找到提及它的任何文档。

这就是我不得不完全测试TestedClass

的原因

通过单元测试

import com.nhaarman.mockito_kotlin.argumentCaptor
import com.nhaarman.mockito_kotlin.inOrder
import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.verifyNoMoreInteractions

@Test
fun save() {
    val testedClass = TestedClass()
    val mockRealm: Realm = mock()
    val objectToBeSaved: RealmModel = mock()
    val captor = argumentCaptor<Realm.Transaction>()

    testedClass.save(mockRealm, objectToBeSaved)

    inOrder(mockRealm).apply {
        verify(mockRealm).executeTransaction(captor.capture())
        verify(mockRealm).close()

        // Now make sure the lambda passed to executeTransaction() does the right thing
        captor.firstValue.execute(mockRealm)

        verify(mockRealm).copyToRealm(objectToBeSaved)
        verifyNoMoreInteractions(mockRealm)
    }
}

答案 1 :(得分:0)

在2.x天里,Realm中有很多最终的类和方法,所以你无法模仿它。

我做了一个简单的包装类来解决它,在我的代码中使用它并嘲笑它

open class RealmInstance(val realm: Realm): Closeable by realm {

    open fun delete(clazz: Class<out RealmModel>) {
        realm.delete(clazz)
    }

    open fun insertOrUpdate(realmModel: RealmModel) {
        realm.insertOrUpdate(realmModel)
    }

    open fun insertOrUpdate(objects: Collection<RealmModel>?) {
        realm.insertOrUpdate(objects)
    }

    open fun <E : RealmModel> where(clazz: Class<E>): RealmQueryInstance<E> {
        return RealmQueryInstance(realm.where(clazz))
    }

    open fun <E: RealmModel> copyFromRealm(realmObject: E): E {
        return realm.copyFromRealm(realmObject)
    }

    open fun beginTransaction() {
        realm.beginTransaction()
    }

    open fun commitTransaction() {
        realm.commitTransaction()
    }

    open fun <T: RealmObject> copyToRealmOrUpdate(realmObject: T): T {
        return realm.copyToRealmOrUpdate(realmObject)
    }

    open fun <T: RealmObject> copyToRealmOrUpdate(realmList: RealmList<T>): List<T> {
        return realm.copyToRealmOrUpdate(realmList)
    }
}

但是现在据我所知,Realm类不再是最终版本了,你应该可以用Mockito来模拟它:

https://realm.io/docs/java/5.0.0/api/