Realm 失败的仪器测试

Instrumented test with Realm failing

我正在实施仪器测试来测试使用 Realm 的数据库数据源 class。所以现在我面临一些关于如何使用固定装置以及如何模拟 Realm 的问题。 我的数据库数据源如下所示:

public class DatabaseDataSource {
    private Realm realm;

    public DatabaseDataSource(Realm realm) {
        this.realm = realm;
    }


    public Observable<RealmResults> getContacts(String firstName, String lastName, String city, String zipCode) {

        final RealmQuery realmQuery = realm.where(Contact.class);
        if(!TextUtils.isEmpty(firstName)) {
            realmQuery.contains("firstName", firstName);
        }
        if(!TextUtils.isEmpty(lastName)) {
            realmQuery.contains("lastName", lastName));
        }
        if(!TextUtils.isEmpty(city)) {
            realmQuery.contains("city", city);
        }
        if(!TextUtils.isEmpty(zipCode)) {
            realmQuery.contains("zipCode", zipCode);
        }

        return realmQuery.findAll()
                    .asObservable();
    }
}

我想在我的模拟领域中有一个联系人列表,这样我就可以检查过滤是否正常工作。我怎样才能做到这一点? 我试过:

@RunWith(AndroidJUnit4.class)
public class DatabaseDataSourceTest extends BaseInstrumentedTest{

    private DatabaseDataSource databaseDataSource;

    private List<Contact> contacts;

    @Before
    public void setup() {
        Realm.init(InstrumentationRegistry.getTargetContext());
        Realm.setDefaultConfiguration(new RealmConfiguration.Builder().build());

        databaseDataSource = new DatabaseDataSource(new DatabaseClient());
    }

    @Test
    public void trial() throws Exception {
        subscribeContactsListObservable(databaseDataSource.getContacts("firstName", null, null, null));

        assertEquals(2, contacts.size());

    }

    private void subscribeContactsListObservable(final Observable<RealmResults> observable) {
        notaries = null;
        observable.map(new Func1<RealmResults, List<Contact>>() {
            @Override
            public List<Notary> call(RealmResults realmResults) {
                return realmResults != null? new ArrayList<>(realmResults) : null;
            }
        }).observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Subscriber<List<Contact>>() {
        @Override
        public void onCompleted() {
            contacts = null;
        }

        @Override
        public void onError(Throwable e) {
            contacts = null;
        }

        @Override
        public void onNext(List<Contact> contactsList) {
            contacts = contactsList;
        }
    });
}

}

但是在执行 Observable.subscribe 时测试失败,但出现以下异常:

You can't register a listener from a non-Looper thread or IntentService thread. 

我可以做什么?

提前致谢

显然你的 getContacts() 方法 运行 在非循环后台线程上,它不适用于我们的更改侦听器(因此我们的 asObservable() 方法)。

您可以只创建可观察对象,但请记住,它会发出您的列表一次,然后完成。要持续更新,您需要在 Looper 线程上。

return Observable.just(realmQuery.findAll());

好吧,它在该错误消息中专门告诉您问题的解决方案:

You can't register a listener from **a non-Looper thread** or IntentService thread. 

这是因为 asObservable() 需要注册一个 RealmChangeListener 才能监听 Realm 中的变化。

检测线程是非循环线程,这意味着您无法监听其中的变化。

解决方案,您需要使用一个Looper 线程(如主线程),或者创建一个Looper 线程,并在该looper 线程中创建Realm 实例。方便的是,RxAndroid 具有所谓的 LooperScheduler which you can create using AndroidSchedulers.from(Looper),它允许您在任意循环线程上执行逻辑。

一种可能性正在研究 Realm already tests their looper-related stuff with this RunInLooperThread test rule

这是我的一项测试的片段:

public class PlaybackDatabaseTest extends ApplicationTestCase<Application> {

    public PlaybackDao dao;

    public PlaybackDatabaseTest(){ super(Application.class);}

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        DatabaseModule module = new DatabaseModule();
        RealmConfiguration config = module.providePlaybackRealmConfiguration(getContext());
        dao = module.providePlaybackDatabase(config);
    }


    public void testAddingPlaylistAndDeletingDatabase() {
        dao.purgeDatabase();
        int id1 = 0;
        Playlist playlist = createTestPlaylist(id1, 0, 100);
        dao.addPlaylist(playlist);
        boolean exist1 = dao.isPlaylistExist(String.valueOf(id1));
        assertTrue(exist1);
        dao.purgeDatabase();
        exist1 = dao.isPlaylistExist(String.valueOf(id1));
        assertFalse(exist1);
    }
}

但是,它使用 Dagger2 创建数据库 'data access object' .

Realm 可以从主线程运行,使用 Observable.toblocking() 所以你的 测试线程将等到 jub 完成。

Realm使用Android的Handler进行并发(.map(), .flatmap() operators return results on Schedulers.computation() by default),所以要解决Handler问题使用 ApplicationTestCase.