Android 虽然域是模拟的,但调用了实际的close()方法
我有一个非常简单的Android 虽然域是模拟的,但调用了实际的close()方法,android,unit-testing,kotlin,realm,mockito,Android,Unit Testing,Kotlin,Realm,Mockito,我有一个非常简单的save()方法来保存realmodel,在保存realm之后。由于不再需要数据库,因此调用close() 问题:调用实际的close()方法,尽管使用mockito模拟Realm。这会导致一个异常: IllegalStateException:来自错误线程的域访问。 领域实例只能在创建它的线程上关闭 莫基托不能模拟王国吗?我不想仅仅为了测试这个案例而包含PowerMock:D 使用realm gradle插件测试 被试班级 import io.realm.Realm imp
save()
方法来保存realmodel
,在保存realm之后。由于不再需要数据库,因此调用close()
问题:调用实际的close()
方法,尽管使用mockito模拟Realm。这会导致一个异常:
IllegalStateException:来自错误线程的域访问。
领域实例只能在创建它的线程上关闭
莫基托不能模拟王国吗?我不想仅仅为了测试这个案例而包含PowerMock:D
使用realm gradle插件测试
被试班级
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()
}
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.x时代,领域中曾经有很多最终的类和方法,所以您无法模拟它
我做了一个简单的包装器类来解决它,在代码中使用它并模拟它
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)
}
}
开放类RealmInstance(val realm:realm):可按领域关闭{
打开乐趣删除(clazz:Class){
realm.delete(clazz)
}
OpenFunInsertorUpdate(realmModel:realmModel){
realm.insertOrUpdate(realmModel)
}
打开趣味插件更新(对象:收藏?){
realm.insertOrUpdate(对象)
}
打开有趣的地方(clazz:Class):RealmQueryInstance{
返回RealmQueryInstance(realm.where(clazz))
}
打开有趣的copyFromRealm(realmObject:E):E{
返回realm.copyFromRealm(realmObject)
}
开放式有趣的开始(){
realm.beginTransaction()
}
open fun commitTransaction(){
realm.commitTransaction()
}
打开有趣的copyToRealmOrUpdate(realmObject:T):T{
返回realm.copyToRealmOrUpdate(realmObject)
}
打开有趣的copyToRealmOrUpdate(realmList:realmList):列表{
返回realm.copyToRealmOrUpdate(realmList)
}
}
但现在就我所见,realm 5的realm
类不再是最终类,你应该可以用Mockito来模拟它:
解决方案是一个新的领域版本
似乎在realm gradle plugin
5.0.0和5.3.1之间的某个地方,这个问题在realm库端得到了解决,尽管我找不到任何关于它的文档
这就是我最后不得不完全测试的TestedClass
通过单元测试
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()
}
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)
}
}
import com.nhaarman.mockito_kotlin.argumentCaptor
导入com.nhaarman.mockito_kotlin.inoorder
导入com.nhaarman.mockito_kotlin.mock
导入com.nhaarman.mockito_kotlin.verifynomore
@试验
趣味储蓄{
val testedClass=testedClass()
val mockRealm:Realm=mock()
val objecttobesave:realmodel=mock()
val captor=argumentCaptor()
testedClass.save(mockRealm,objecttobesave)
inoorder(mockRealm).apply{
验证(mockRealm).executeTransaction(captor.capture())
验证(mockRealm.close())
//现在,请确保传递给executeTransaction()的lambda执行正确的操作
captor.firstValue.execute(mockRealm)
验证(mockRealm).copyToRealm(objectToBeSaved)
verifyNoMoreInteractions(mockRealm)
}
}
你尝试过类似于Mockito.when(mockRealm.close()).doNothing()之类的东西吗?是的,我尝试过doNothing()。where(mockRealm.close()
你使用的是哪个领域版本?我使用的是5.0.0版本,我更新了我的问题以反映这一点,并且我给出了一个适用于新版本的答案。