Модульное тестирование Android с помощью ContentProviders - PullRequest
4 голосов
/ 11 января 2012

Я уже давно борюсь с проблемой юнит-тестирования на Android.Мое приложение использует Sqlite DB для хранения информации о транспортных средствах.Недавно я добавил шаблон ContentProvider для извлечения данных (база данных использовалась для прямого доступа).

Приложение работает нормально, но мои тесты время от времени терпят неудачу при запуске в режиме «запуска» на затмении - они проходят в'режим отладки.В моем методе setUp () я создаю RenamingDelegatingContext, чтобы создать тестовую версию моей базы данных.Все это делает префикс «тест».к имени моей базы данных, чтобы убедиться, что тестовая программа не затрагивает «настоящую» базу данных.Затем я передаю это в класс «провайдера данных», чтобы сохранить в качестве переменной экземпляра до тех пор, пока не будет вызван первый вызов getWriteableDatabase ():

public class VehicleProviderTest extends InstrumentationTestCase
{

RenamingDelegatingContext renamingDelegatingContext;
@Override
protected void setUp() throws Exception
{
    super.setUp();
    if(null == renamingDelegatingContext)
    {
        renamingDelegatingContext = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), "test.");

    }

    Log.d("UKMPG", "Initialising UKMPGDataProvider with test context: " + renamingDelegatingContext.getClass().toString());
    MPGDataProvider.init(getTestContext(), Constants.DATABASE_NAME);
    deleteTestDatabase();
}
}

Метод onCreate () моего ContentProvider выполняет аналогичную работу в том, что онтакже передает Контекст классу поставщика данных:

    @Override
public boolean onCreate()
{
    Context context = getContext();
    Log.d("UKMPG", "ContentProvider.onCreate called. Context: " + context.getClass().toString());
    MPGDataProvider.init(getContext(), Constants.DATABASE_NAME);
    return true;
}

Теперь проблема;когда я запускаю свои тесты (опять же, это не происходит в режиме отладки), onCreate () в моем ContentProvider вызывается после мой метод setUp () передал RenamingDelegatingContext классу поставщика данных, в результате чегоэто перезаписывается.Это означает, что для тестов будет использоваться действующая база данных (они потерпят неудачу, поскольку тесты ожидают пустую базу данных).

Вот некоторый logcat, показывающий происходящую перезапись с примечаниями, объясняющими, что происходит:

ContentProvider.onCreate вызывается и передает контекст в UKMPGDataProvider:

01-11 19:22:11.404: D/UKMPG(480): ContentProvider.onCreate called. Context: class android.app.Application
01-11 19:22:11.414: D/UKMPG(480): UKMPGDataProvider.init called. Context: class android.app.Application, db name :mpg_tracker.db

Тесты передают RenamingDelegatingContext в UKMPGDataProvider:

01-11 19:22:13.234: D/UKMPG(498): Initialising UKMPGDataProvider with test context: class android.test.RenamingDelegatingContext
01-11 19:22:13.234: D/UKMPG(498): UKMPGDataProvider.init called. Context: class android.test.RenamingDelegatingContext, db name :mpg_tracker.db

ContentProvider.onCreate вызывается снова (другой PID) и передает ApplicationContext вUKMPGDataProvider, перезаписывающий RenamingDelegatingContext:

01-11 19:22:13.254: D/UKMPG(498): ContentProvider.onCreate called. Context: class android.app.ApplicationContext
01-11 19:22:13.254: D/UKMPG(498): UKMPGDataProvider.init called. Context: class android.app.ApplicationContext, db name :mpg_tracker.db

Произошел первый вызов getWriteableDatabase (), поэтому база данных будет создана с неверным контекстом:

01-11 19:22:13.265: D/UKMPG(498): database null - going to create it

Еще один вызов ContentProvider.Создание произошло!На этот раз с обычным контекстом.Однако ущерб уже нанесен, так что на самом деле это ничего не меняет:

01-11 19:22:13.265: D/UKMPG(498): ContentProvider.onCreate called. Context: class android.app.Application

Создание БД с неверным контекстом:

01-11 19:22:13.265: D/UKMPG(498): Creating DB instance with Context: class android.app.ApplicationContext

init () метод, вызываемый в соответствии с последнимВызов ContentProvider.onCreate ():

01-11 19:22:13.274: D/UKMPG(498): UKMPGDataProvider.init called. Context: class android.app.Application, db name :mpg_tracker.db

getWriteableDatabase () возвращает не тестовую базу данных:

01-11 19:22:13.374: D/UKMPG(498): getWritableDatabase. Path of returned db: /data/data/barry.contentproviderexample/databases/mpg_tracker.db

Не удалось удалить базу данных для следующего теста, как это делает база данных 'test'не существует:

01-11 19:22:13.615: D/UKMPG(498): Database deleted:false

Для полноты, вот logcat из того же тестового прогона при запуске в режиме отладки:

01-11 19:37:09.514: D/UKMPG(598): ContentProvider.onCreate called. Context: class android.app.Application
01-11 19:37:09.514: D/UKMPG(598): UKMPGDataProvider.init called. Context: class android.app.Application, db name :mpg_tracker.db
01-11 19:37:11.313: D/UKMPG(616): ContentProvider.onCreate called. Context: class android.app.Application
01-11 19:37:11.313: D/UKMPG(616): UKMPGDataProvider.init called. Context: class android.app.Application, db name :mpg_tracker.db

В этот момент ContentProder.onCreate был вызван дважды сне тестовый контекст, но это происходит до моего метода setUp (), поэтому он не влияет на тесты:

01-11 19:37:14.173: D/UKMPG(616): Initialising UKMPGDataProvider with test context: class android.test.RenamingDelegatingContext
01-11 19:37:14.173: D/UKMPG(616): UKMPGDataProvider.init called. Context: class android.test.RenamingDelegatingContext, db name :mpg_tracker.db
01-11 19:37:14.213: D/UKMPG(616): database null - going to create it
01-11 19:37:14.213: D/UKMPG(616): Creating DB instance with Context: class android.test.RenamingDelegatingContext
01-11 19:37:14.364: D/UKMPG(616): getWritableDatabase. Path of returned db: /data/data/barry.contentproviderexample/databases/test.mpg_tracker.db
01-11 19:37:14.794: D/UKMPG(616): Database deleted:true

Может кто-нибудь помочь мне понять это?Я что-то не так делаю, или это (многопоточность) ошибка в Android?

Это повторяется на устройствах и на версиях Android от 1.6 до 4.0.

1 Ответ

2 голосов
/ 12 января 2012

Я думаю, вам следует вызвать setContext () в вашем setUp ():

// warning: untested code
protected void setUp() throws Exception
{
    super.setUp();
    setContext(new RenamingDelegatingContext(getTargetContext(), "test.");

    ...
}

В этом случае вам может потребоваться изменить базовый класс на ProviderTestCase2 , вероятно.

...