Mockito测试RealmObject类报错:Realm模型类测试方法咨询
如何用Mockito测试Realm模型类(RealmObject子类)
我完全懂你遇到的坑——直接用Mockito mock或者spy继承自RealmObject的类总会报错,这可不是你的问题,是Realm的动态代理机制在搞事情!
为什么会报错?
Realm在运行时会给每个RealmObject子类自动生成一个代理子类,用来实现它的持久化、懒加载这些核心逻辑。而Mockito原生没法正确处理这种动态生成的代理类,不管是mock原始类还是spy真实对象,都会因为类加载或者代理冲突抛出异常。
给你三个可行的解决方案,按推荐程度排序:
1. 用接口封装Realm模型(最推荐)
如果你的测试只关注业务逻辑,不需要和Realm的持久化交互,最省心的方式是给Foo定义一个接口,让Foo实现它,然后mock这个接口就行:
首先定义接口:
public interface FooContract { String getPK(); Stuff getStuff(); int getNum(); }
修改Foo类实现接口:
public class Foo extends RealmObject implements FooContract { @PrimaryKey private String PK; // 补上原代码缺失的getPK方法 public String getPK() { return PK; } public Stuff getStuff(){ return new Stuff(); } public int getNum(){ return 1; } }
测试时直接mock接口:
@Test public void clearObject(){ FooContract mockFoo = mock(FooContract.class); // 正常设置mock行为,比如: when(mockFoo.getNum()).thenReturn(100); assertEquals(100, mockFoo.getNum()); }
2. 用Realm官方测试框架(需要测试Realm交互时用)
如果你的测试需要验证和Realm的交互逻辑(比如保存、查询),别硬扛Mockito,用Realm自己的测试库更靠谱:
首先在build.gradle里添加测试依赖(版本和你项目里的Realm保持一致):
testImplementation 'io.realm:realm-testing-library:10.15.1'
然后编写测试,用内存中的Realm实例来创建真实对象,再配合spy:
import org.junit.After; import org.junit.Before; import org.junit.Test; import io.realm.Realm; import io.realm.RealmConfiguration; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.doReturn; import static org.junit.Assert.assertEquals; public class FooRealmTest { private Realm realm; @Before public void setUp() { // 创建内存版Realm,测试数据不会写到磁盘 RealmConfiguration testConfig = new RealmConfiguration.Builder() .inMemory() .name("test-realm") .build(); Realm.setDefaultConfiguration(testConfig); realm = Realm.getDefaultInstance(); } @Test public void spyOnRealmObject() { // 在Realm中创建真实的Foo对象 realm.beginTransaction(); Foo foo = realm.createObject(Foo.class, "test-pk-123"); realm.commitTransaction(); // 用spy包装真实对象,修改指定方法的返回值 Foo spyFoo = spy(foo); doReturn(99).when(spyFoo).getNum(); assertEquals(99, spyFoo.getNum()); // 其他方法还是会调用真实实现,比如getStuff() } @After public void tearDown() { if (realm != null) { realm.close(); // 清理内存中的Realm数据 Realm.deleteRealm(Realm.getDefaultConfiguration()); } } }
3. 用PowerMock硬刚(不推荐,仅作备选)
如果一定要直接mockRealmObject子类,可以用PowerMock来绕过类加载限制,但这种方式会增加测试复杂度,还容易和Mockito版本冲突:
@RunWith(PowerMockRunner.class) @PrepareForTest({Realm.class, Foo.class}) public class FooPowerMockTest { @Test public void mockFooDirectly() { Foo mockFoo = mock(Foo.class); when(mockFoo.getNum()).thenReturn(5); assertEquals(5, mockFoo.getNum()); } }
总结
优先选接口封装或者Realm测试框架的方案,尽量别直接mockRealmObject子类——Realm的动态代理和普通Java类差异太大,Mockito原生确实搞不定它。
内容的提问来源于stack exchange,提问作者Arvalon
相关产品推荐
相关产品推荐

