【问题标题】:Actual close() method is called although Realm is mocked尽管 Realm 被模拟,但实际的 close() 方法被调用
【发布时间】:2018-04-05 08:17:23
【问题描述】:

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

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

IllegalStateException:来自错误线程的领域访问。 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()
}

【问题讨论】:

  • 你试过Mockito.when(mockRealm.close()).doNothing()之类的吗?
  • 是的,我试过doNothing().whenever(mockRealm).close()
  • 您使用的是什么版本的领域?
  • 我使用的是 5.0.0 版,我更新了我的问题以反映这一点,并且我给出了适用于较新版本的答案。

标签: android unit-testing kotlin realm mockito


【解决方案1】:

解决方案是一个新的 Realm 版本。

似乎在realm-gradle-plugin 5.0.05.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)
    }
}

【讨论】:

    【解决方案2】:

    在 2.x 时代,Realm 中有很多 final 类和方法,所以你无法模拟它。

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

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

    但现在据我所知,在领域 5 中,Realm 类不再是最终的,您应该可以使用 Mockito 来模拟它:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-20
      • 1970-01-01
      • 2017-06-25
      • 1970-01-01
      • 1970-01-01
      • 2016-03-31
      相关资源
      最近更新 更多