Я уже давно борюсь с проблемой юнит-тестирования на 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.