2013-08-02 5 views
12

Я заметил, что время от времени возникает вопрос об использовании Robolectric для тестирования пользовательских ContentProviders. Тем не менее, никогда не было конкретного и однозначного ответа о том, как это сделать должным образом. Я наткнулся на 2 разных подходов:Robolectric ContentProvider testing

Однако я получаю java.lang.InstantiationException с обоих подходов. Были некоторые сообщения SO, в которых говорилось, что это связано с тем, что SQLiteDatabase.rawQueryWithFactory (SQLiteDatabase.java) не переопределяется в Robolectric (Android + Robolectric - RuntimeException/InstantiationException in queryBuilder.query() in ContentProvider).

Я думаю, мой вопрос в том, есть ли превентивные обходные пути, которые делают тестирование ContentProviders возможным. Или есть другие подходы, которые лучше, чем те, которые упомянуты выше.

+0

Предлагаю не использовать первую ссылку вообще - код полностью тупой и даже не компилируется. –

ответ

5

Все, что вам нужно сделать, настроено ShadowContentResolver перед испытанием, поэтому оно будет надлежащим образом связывать полномочия вашего ContentProvider с ContentProvider. Вот пример:

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

Самый простой способ поместить этот материал в какой-то @Before аннотированный метод настройки. Однако, более правильный (и, следовательно, лучший в долгосрочной перспективе) способ заключается в том, чтобы поместить это в ваш метод TestApplication#onCreate, поэтому эта конфигурация будет использоваться всеми тестами в вашем приложении.

+0

Я поставил вышеуказанный код в 'TestApplication # onCreate', но не смог использовать контент-провайдер для всех тестов. После первого теста база данных будет удалена: https://github.com/robolectric/robolectric/issues/1082. Удалось ли вам провести более 2 тестов для поставщика контента с помощью Robolectric? –

+1

@HieuRocker да, я. Если я правильно вас понял, значит, вы немного ошибаетесь - это должно быть ожидаемым поведением для тестов для очистки после выполнения. Просто создавайте свою базу данных каждый раз в некотором методе '@ Before' –

+0

W00t, я мог бы исправить проблему на основе вашего намека. Оказалось, это произошло потому, что в ContentProvider я инициализировал 'SQLiteOpenHelper', используя одноэлементный шаблон. Это приводит к тому, что Robolectric не смог воссоздать базу данных для каждого теста. Большое спасибо. –

10

Это испытание Robolectric, что работал хорошо для меня:

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

Спасибо за ваш ответ. Я больше полагаюсь на изучение Android с помощью robolectric. Я устал ходить взад и вперед с эмулятором. И этот ответ помогает пользователю и тестовому контенту. :) –

+4

Обратите внимание, что этот ответ предназначен для RoboElectric 2.4, если вы используете 3.0, используйте https://github.com/robolectric/robolectric/wiki/2.4-to-3.0-Upgrade-Guide, чтобы найти 3,0 эквивалента. – Benjamin

+0

@Benjamin Знаете ли вы, если есть пример с использованием 3.0? Единственные изменения, которые вы должны внести, - это имена классов и аннотаций? Вот те изменения, которые я интерпретировал из документа -> измените тестовый бегун на RoboelectricGradleTestRunner и, возможно, измените getApplication на getShadowApplication. Это верно? – user1743524