android - 当我插入数据库时​​,Realm 抛出 NullPointerException

标签 android unit-testing junit realm

我有一个 RealmManager 类,其中有几个方法可以执行 CRUD。这是我在此类中的 save 方法。

public void save(final List<PointOfInterest> pointOfInterestList) {
    if (mRealm == null || pointOfInterestList == null || pointOfInterestList.isEmpty()) {
        return;
    }

    mRealm.executeTransaction(new Realm.Transaction() { // <= line 155, java.lang.NullPointerException points to this line
        @Override
        public void execute(Realm realm) {
            realm.insertOrUpdate(pointOfInterestList);
        }
    });
}

我写了一个junit测试来测试它。

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 19)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
@SuppressStaticInitializationFor("io.realm.internal.Util")
@PrepareForTest({Realm.class, RealmLog.class})
public class RealmPOIManagerTest
{

    @Rule
    public PowerMockRule rule = new PowerMockRule();
    private Realm mockRealm;

    @Before
    public void setUp() throws Exception
    {
        mockStatic(RealmLog.class);
        mockStatic(Realm.class);

        Realm mockRealm = PowerMockito.mock(Realm.class);
        when(Realm.getDefaultInstance()).thenReturn(mockRealm);

        this.mockRealm = mockRealm;
    }

    @Test
    public void shouldVerifyThatPOIWasCreated() {
        List<PointOfInterest> poiList = new ArrayList<>(1);

        doCallRealMethod().when(mockRealm).executeTransaction(Mockito.any(Realm.Transaction.class));

        PointOfInterest pointOfInterest = mock(PointOfInterest.class);
        when(mockRealm.createObject(PointOfInterest.class)).thenReturn(pointOfInterest);

        poiList.add(pointOfInterest);
        RealmPOIManager.getInstance().save(poiList);

        // Verify that Realm#createObject was called only once and
        // Verify that a PointOfInterest was in fact created.
        verify(mockRealm, times(1)).insertOrUpdate(poiList);
    }

    @Test
    public void shouldVerifyCRUD()
    {
        List<PointOfInterest> poiList = getCollectionOfPOIs();

        // Create list elements
        RealmPOIManager.getInstance().save(poiList); // <= line 112

        // Read a POI item from db based on id
        PointOfInterest result = RealmPOIManager.getInstance().loadPOIByBookingId("1");

        // Make sure retrieved POI is as same as the original item
        assertThat(poiList.get(0), is(result));

        // Update POI, save it and make sure the item has been updated
        result.setUid("4");
        List<PointOfInterest> list = new ArrayList<>(1);
        list.add(result);
        RealmPOIManager.getInstance().save(list);
        PointOfInterest result2 = RealmPOIManager.getInstance().loadPOIByBookingId("4");
        assertThat(result, is(result2));
        PointOfInterest result3 = RealmPOIManager.getInstance().loadPOIByBookingId("1");
        assertNull(result3);
    }

    private List<PointOfInterest> getCollectionOfPOIs()
    {
        List<PointOfInterest> poiList = new ArrayList<>(3);

        PointOfInterest poi1 = new PointOfInterest();
        poi1.setUid("1");

        PointOfInterest poi2 = new PointOfInterest();
        poi2.setUid("2");

        PointOfInterest poi3 = new PointOfInterest();
        poi3.setUid("3");

        poiList.add(poi1);
        poiList.add(poi2);
        poiList.add(poi3);

        return poiList;
    }
}

第一个测试 shouldVerifyThatPOIWasCreated 成功通过,而第二个测试失败。这是在日志中看到的内容:

java.lang.NullPointerException
    at io.realm.BaseRealm.beginTransaction(BaseRealm.java:337)
    at io.realm.Realm.beginTransaction(Realm.java:122)
    at io.realm.Realm.executeTransaction(Realm.java:1087)
    at com.my.package.db.dao.RealmPOIManager.save(RealmPOIManager.java:155)
    at com.my.package.sdk.db.dao.RealmPOIManagerTest.shouldVerifyCRUD(RealmPOIManagerTest.java:112)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.powermock.modules.junit4.rule.PowerMockStatement$1.run(PowerMockRule.java:65)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.powermock.reflect.internal.WhiteboxImpl.performMethodInvocation(WhiteboxImpl.java:1873)
    at org.powermock.reflect.internal.WhiteboxImpl.doInvokeMethod(WhiteboxImpl.java:773)
    at org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:638)
    at org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:401)
    at org.powermock.classloading.ClassloaderExecutor.execute(ClassloaderExecutor.java:98)
    at org.powermock.classloading.ClassloaderExecutor.execute(ClassloaderExecutor.java:78)
    at org.powermock.modules.junit4.rule.PowerMockStatement.evaluate(PowerMockRule.java:57)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:251)
    at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
    at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)


Process finished with exit code 255

更新

这是我的 PointOfInterest 类(class)的一部分。

@Parcel
@RealmClass
public class PointOfInterest implements RealmModel {
    public static final String REALM_KEY_UID = "uid";

    @Required // Throw exception if BookingId is `null`
    @PrimaryKey
    String uid;

...
}

最佳答案

Realm 在单元测试中不起作用。 Realm 的 github 上的单元测试示例显示 Realm 被模拟了,因为 Realm 不能在 Android 之外工作。

要测试 Realm 特定的行为,您需要使用仪器测试。

(这基本上意味着

 doCallRealMethod().when(mockRealm).executeTransaction(Mockito.any(Realm.Transaction.class));

这行不通,在非 Android JVM 上下文中调用的真实方法将失败。)

关于android - 当我插入数据库时​​,Realm 抛出 NullPointerException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39646618/

相关文章:

android - 使用mockito测试void方法

java - 在 IntelliJ IDEA 2018.1 中运行 JUnit 5 测试时出错

java - 将 NullPointerException 视为单元测试失败 : is it good practice?

android - Chrome Web Audio API-如何在通话中播放声音

android - 如何在工具栏下方创建一个 TabLayout 位置?

java - 如何对使用 session 窗口的 kafka 流应用程序进行单元测试

ios - 使用示例核心数据进行单元测试

java - JMock 期望中的第二组括号

android - 带有 ImageView 和 TextView 的 Android fragment 的自定义适配器

android - 有人知道有多少 Android 设备支持 NEON 吗?