2016-10-27 3 views
0

Ich implementiere einen instrumentierten Test, um eine Datenbank-Datenquellenklasse zu testen, die Realm verwendet. So, jetzt habe ich einige Probleme, wie man Fixtures benutzt und wie man Realm verspottet. Meine Datenbank-Datenquelle wie folgt aussieht:Instrumentierter Test mit Realm fehlgeschlagen

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(); 
    } 
} 

ich eine Liste von Kontakten in meinem verspottet Reich haben will, damit ich, dass die Filterung funktioniert prima überprüfen. Wie kann ich das machen? Ich habe versucht zu tun:

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

}

Aber der Test nicht bestehen, wenn die Observable.subscribe mit folgenden Ausnahme machen:

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

Was kann ich tun?

Vielen Dank im Voraus

Antwort

0

Nun sagt Ihnen, es speziell die Lösung für Ihr Problem, dass die Fehlermeldung:

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

Dies liegt daran, asObservable() Bedürfnisse ein RealmChangeListener zu registrieren, um auf Veränderungen im Reich zu hören.

Der Instrumentierungs-Thread ist ein Nicht-Looper-Thread, das bedeutet, dass Sie Änderungen nicht abhören können.

Lösung, Sie müssen entweder einen Looper-Thread (wie der Haupt-Thread) verwenden oder einen Looper-Thread erstellen und die Realm-Instanz in diesem Looper-Thread erstellen. Praktischerweise bietet RxAndroid einen sogenannten LooperScheduler, den Sie mit AndroidSchedulers.from(Looper) erstellen können, mit dem Sie Logik auf einem beliebigen Looper-Thread ausführen können.

Eine Möglichkeit untersucht wie Realm already tests their looper-related stuff with this RunInLooperThread test rule.

+1

Vielen Dank, ich habe es gelöst mit: InstrumentationRegistry .getInstrumentation(). runOnMainSync() – FVod

+0

Das funktioniert auch, der Haupt-Thread ist ein Looper-Thread :) – EpicPandaForce

0

Anscheinend führen Sie Ihre getContacts() Methoden auf einem Nicht-Looper Hintergrund-Thread, die mit unserer Änderung Hörer nicht funktioniert (und damit unsere asObservable() Methode).

Sie können stattdessen nur das Observable erstellen, aber bedenken Sie, dass es Ihre Liste einmal ausgibt und dann vervollständigt. Für kontinuierliche Updates müssen Sie sich auf einem Looper-Thread befinden.

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

Vielen Dank für Ihre Antwort. Was ist der Unterschied zwischen dem Observable.just und dem .asObservable()? Was bedeutet diese Änderung? – FVod

+0

'asObservable()' ist ein Wrapper um unsere Change-Listener. Dies bedeutet, dass das Observable-Objekt niemals abgeschlossen wird und jedes Mal ausgegeben wird, wenn sich das Abfrageergebnis ändert. 'Observable.just()' gibt das Abfrageergebnis einmal aus und wird abgeschlossen. Ich konnte anhand deines Codes nicht erkennen, ob das akzeptabel war. Wenn nicht, müssen Sie einen Weg finden, die Methode stattdessen in einem Looper-Thread auszuführen. Wenn Sie Bedenken haben, die Benutzeroberfläche zu blockieren, können Sie stattdessen 'query.findAllAsync(). AsObservable() 'ausführen und die Abfrage wird automatisch auf einem Hintergrund-Thread ausgeführt. –

+0

Hallo, ich hatte Probleme mit findAllAsync() es immer Null an meinen Abonnenten zurückgegeben :( – FVod

0

Hier Fragment eines meiner Tests:

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); 
    } 
} 

Aber es Dagger2 verwenden, um Datenbank 'Datenzugriffsobjekt' zu erstellen.

Realm kann vom Hauptthread aus arbeiten, verwenden Sie Observable.toblocking(), so dass Ihr Test-Thread wartet, bis Jub beendet ist.

Realm verwenden Android Handler für Parallelität (.map(), .flatmap() -Operatoren geben Ergebnisse auf Schedulers.computation() als Standard), so zu Handler Problem ApplicationTestCase zu lösen.

+0

Danke für Deine Antwort. ApplicationTestCase ist veraltet, daher möchte ich das nicht verwenden. Ich habe versucht, an der Beobachtungsstelle vor dem Abonnement toblocking() hinzuzufügen, aber der Fehler ändert sich nicht – FVod

Verwandte Themen