2013-08-02 12 views
12

Ich habe festgestellt, dass ab und zu eine Frage zur Verwendung von Robolectric zum Testen von benutzerdefinierten ContentProvidern auftritt. Es gab jedoch nie eine konkrete und eindeutige Antwort darauf, wie man es richtig macht. Ich habe auf zwei verschiedene Ansätze gestolpert:Robolectric ContentProvider testing

Allerdings bin ich ein java.lang.InstantiationException mit beiden Ansätzen zu bekommen. Es gab einige SO-Posts, die besagen, dass dies darauf zurückzuführen ist, dass SQLiteDatabase.rawQueryWithFactory (SQLiteDatabase.java) in Robolectric nicht überschrieben wurde (Android + Robolectric - RuntimeException/InstantiationException in queryBuilder.query() in ContentProvider).

Ich denke, meine Frage ist - gibt es irgendwelche preferred Problemumgehungen, die Testing ContentProviders möglich machen. Oder gibt es andere Ansätze, die besser sind als die oben genannten?

+0

Ich schlage vor, nicht den ersten Link überhaupt zu verwenden - Code dort ist völlig dumm und wird nicht einmal kompilieren. –

Antwort

5

Alles, was Sie tun müssen, ist ShadowContentResolver vor dem Test eingerichtet, damit es die Autorität Ihrer ContentProvider mit ContentProvider selbst ordnungsgemäß zuordnen. Hier ein Beispiel:

ShadowContentResolver.registerProvider(
     "com.example.provider", //authority of your provider 
     contentProvider //instance of your ContentProvider (you can just use default constructor)  
); 

Der einfachste Weg ist, dieses Zeug in eine @Before kommentierten Set-up-Methode zu setzen. Jedoch ist die korrektere (und daher auf lange Sicht bessere) Methode, dies in Ihre TestApplication#onCreate Methode zu übertragen, so dass diese Konfiguration von allen Tests in Ihrer Anwendung verwendet wird.

+0

Ich habe den obigen Code in 'TestApplication # onCreate' gesetzt, konnte aber den Content Provider nicht für alle Tests verwenden. Nach dem ersten Test wird die Datenbank entfernt: https://github.com/robolectric/robolectric/issues/1082. Hattest du Erfolg mit mehr als 2 Tests für Content Provider mit Robolectric? –

+1

@HieuRocker ja, das tue ich. Wenn ich dich richtig verstanden habe, dann hast du es ein bisschen falsch verstanden - das sollte erwartet werden, dass Tests nach der Ausführung bereinigt werden. Erstellen Sie Ihre Datenbank jedes Mal in einer @ @ Before-Methode –

+0

W00t, ich könnte das Problem basierend auf Ihrem Hinweis beheben. Es stellte sich heraus, dass ich im ContentProvider 'SQLiteOpenHelper' mit Singleton-Pattern initialisiert habe. Dies führt dazu, dass Robolectric die Datenbank für jeden Test nicht neu erstellen konnte. Danke vielmals. –

10

Dies ist der Robolectric Test, der gut für mich gearbeitet:

import android.content.ContentResolver; 
import android.database.Cursor; 
import android.net.Uri; 

import org.joda.time.LocalDate; 
import org.junit.Before; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.robolectric.Robolectric; 
import org.robolectric.RobolectricTestRunner; 
import org.robolectric.annotation.Config; 
import org.robolectric.shadows.ShadowContentResolver; 

import co.tomup.app.db.DbSchema; 
import co.tomup.app.db.TomupContentProvider; 
import co.tomup.app.db.model.CalendarDay; 
import co.tomup.app.db.tables.CalendarDayTable; 

import static org.junit.Assert.assertEquals; 
import static org.junit.Assert.assertTrue; 

@Config(emulateSdk = 18) 
@RunWith(RobolectricTestRunner.class) 
public class CalendarDayProviderTest { 

    private ContentResolver mContentResolver; 
    private ShadowContentResolver mShadowContentResolver; 
    private TomupContentProvider mProvider; 

    @Before 
    public void setup() { 
     mProvider = new TomupContentProvider(); 
     mContentResolver = Robolectric.application.getContentResolver(); 
     mShadowContentResolver = Robolectric.shadowOf(mContentResolver); 
     mProvider.onCreate(); 
     ShadowContentResolver.registerProvider(DbSchema.AUTHORITY, mProvider); 
    } 

    @Test 
    public void testInsertAndDelete() { 
     // insert 
     CalendarDay calendarDay = new CalendarDay(); 
     calendarDay.setId(1L); 
     calendarDay.setDay(new LocalDate()); 
     calendarDay.setMoonPhase("new"); 
     calendarDay.setSunrise(1); 
     calendarDay.setSunset(100); 
     Uri insertionId = mContentResolver.insert(CalendarDayTable.CONTENT_URI, 
       calendarDay.toSQLiteContentValues()); 
     Cursor cursorCheck = mShadowContentResolver.query(CalendarDayTable.CONTENT_URI, 
       null, null, null, null); 
     while (cursorCheck.moveToNext()) { 
      CalendarDay calendarDayCheck = CalendarDay.fromSQLiteCursor(cursorCheck); 
      assertEquals(calendarDay, calendarDayCheck); 
     } 
     assertTrue(cursorCheck.getCount() > 0); 
     // delete 
     mShadowContentResolver.delete(insertionId, 
       null, null); 
     cursorCheck = mShadowContentResolver.query(CalendarDayTable.CONTENT_URI, 
       null, null, null, null); 
     assertTrue(cursorCheck.getCount() == 0); 
    } 
} 
+0

Danke für Ihre Antwort. Ich verlasse mich mehr darauf Android mit robolectric zu lernen. Ich bin es leid, mit dem Emulator hin und her zu gehen. Und diese Antwort hilft mir, den Contentprovider zu benutzen und zu testen. :) –

+4

Hinweis: Diese Antwort gilt für RoboElectric 2.4. Wenn Sie 3.0 verwenden, verwenden Sie https://github.com/robolectric/robolectric/wiki/2.4-to-.0-Upgrade-Guide, um die 3.0-Äquivalente zu finden. – Benjamin

+0

@Benjamin wissen Sie, ob es ein Beispiel mit 3.0 gibt? Sind die einzigen Änderungen, die Sie vornehmen müssen, die Klassen- und Annotationsnamen? Hier sind die Änderungen, die ich aus dem Dokument interpretiert habe -> Ändere den Test-Runner zu RoboelectricGradleTestRunner und ändere vielleicht getApplication zu getShadowApplication. Ist das korrekt? – user1743524

Verwandte Themen