Testing findAllAsync asChangesetObservable queries with RunTestInLooperThread
See original GitHub issueHi, guys! Thank you for your product. I am trying to write unit-tests for my DAO classes, that uses Realm. I use RunInLooperThread rule like in your RealmAsyncQueryTests class to test methods with findAllAsync calls. And i got the problem with RealmResults returned during the test.
Goal
I would like to get loaded RealmResults after results.addChangeListener(listener); is called under the hood of asChangesetObservable.
Expected Results
First emit contains not loaded RealmResults, according to emitter.onNext(new CollectionChange<>(results, null)); in changesetsFrom implementation. But second emit should contain loaded RealmResults according to documentation
Actual Results
I got RealmResults with isLoaded = false and it contains my data. RealmResults with isLoaded = true will never be returned from Observable.
E.g. full stack trace with exception java.lang.AssertionError: Expected: [com.wayray.element.core.data.CarData@0] (class: SingletonList), Actual: [] (latch = 1, values = 0, errors = 0, completions = 0, timeout!) at io.reactivex.observers.BaseTestConsumer.fail(BaseTestConsumer.java:191) at io.reactivex.observers.BaseTestConsumer.assertValue(BaseTestConsumer.java:356) at com.wayray.element.core.dao.CharacteristicDaoTest.test_getUserCharacteristicsByName(CharacteristicDaoTest.java:44) at java.lang.reflect.Method.invoke(Native Method) 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 io.realm.rule.RunInLooperThread$TestThread.run(RunInLooperThread.java:509)
Steps & Code to Reproduce
Describe your current debugging efforts.
Code Sample
@RunWith(AndroidJUnit4.class)
public class CharacteristicDaoTest {
@Rule
public final RunInLooperThread looperThread = new RunInLooperThread(new ElementRealmLibraryModule());
@RunTestInLooperThread
@Test
public final void test_getUserCharacteristicsByName() {
CarData carData = new CarData();
TestObserver<List<CarData>> testObserver = new TestObserver<>();
Realm realm = looperThread.getRealm();
realm.executeTransaction(realm1 -> realm1.copyToRealm(carData));
realm
.where(CarData.class)
.findAllAsync()
.asChangesetObservable()
.map(CollectionChange::getCollection)
.filter(RealmResults::isLoaded)
.map(realm::copyFromRealm)
.doOnDispose(realm::close)
.subscribe(testObserver);
testObserver.awaitCount(1);
testObserver.assertValue(Collections.singletonList(carData));
testObserver.dispose();
looperThread.testComplete();
}
}
Version of Realm and tooling
Realm version(s): ? 5.1.0 Realm sync feature enabled: yes/no no Android Studio version: ? 3.1.2 Which Android version and device: ? Emulator with Android P
Could you possibly explain why this test fails, however this code works in the project?
Issue Analytics
- State:
- Created 5 years ago
- Comments:7 (3 by maintainers)
I suspect you are blocking the looper thread with your
testObserver.awaitCount(1)
. If that method is callingCountDownLatch.await()
you are blocking the looper thread from processing any notifications which is why your test times out.This is also why you almost always see our own tests call
looperThread.testComplete()
from inside a callback. Example: https://github.com/realm/realm-java/blob/master/realm/realm-library/src/androidTest/java/io/realm/RxJavaTests.java#L188Thank you very much! You are totally right. After replacing TestObserver with custom Consumer like this:
my test finished with success.