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

时间:2016-09-22 18:42:15

标签: 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类的一部分。

@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;

...
}

2 个答案:

答案 0 :(得分:1)

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

要测试特定于Realm的行为,您需要使用检测测试。

(这实质上意味着

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

这不起作用,在非Android JVM上下文中调用的实际方法将失败。)

答案 1 :(得分:0)

您需要在List<PointOfInterest> pointOfInterestList内再次提取public void execute(Realm realm)

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

        // fetch objects
        List<PointOfInterest> poiList = realm.where.....

        realm.insertOrUpdate(poiList);
    }
});

https://realm.io/news/threading-deep-dive/