Модульные Тесты Android, Требующие Контекста
Я пишу свой первый бэкэнд базы данных Android, и я изо всех сил пытаюсь тестировать создание моей базы данных.
В настоящее время проблема, с которой я сталкиваюсь, - это получение допустимого объекта контекста для передачи моей реализации SQLiteOpenHelper. Есть ли способ получить объект контекста в классе, расширяющем TestCase? Решение, о котором я подумал, заключается в создании экземпляра действия в методе установки моего тестового случая, а затем присвоении контекста этого действия переменной поля что мои методы тестирования могут получить доступ...но, похоже, должен быть более простой способ.
Спасибо за Ваш вклад!
Мэйси
8 ответов:
вы можете попробовать переключиться на AndroidTestCase. Глядя на документы, кажется, что он должен быть в состоянии предоставить вам действительный контекст для передачи в SQLiteOpenHelper.
изменить: Имейте в виду, что вам, вероятно, придется настроить свои тесты в "тестовом проекте Android" в Eclipse, так как тесты будут пытаться выполнить на эмуляторе (или реальном устройстве).
если вы запускаете свои тесты с
AndroidJUnit4, вы можете использоватьInstrumentationRegistryметоды для получения контекста:
InstrumentationRegistry.getTargetContext()- обеспечивает применениеContextцелевого приложения.
InstrumentationRegistry.getContext()обеспечиваетContextиз пакета этого инструментария.
С помощью
AndroidTestCase:getContext()метод только дает заглушку контекст в моем опыте. Для моих тестов я использую пустую активность в своем основном приложении и получаюContextчерез это. Я также расширяю класс набора тестов с помощьюActivityInstrumentationTestCase2класса. Кажется, работает на меня.public class DatabaseTest extends ActivityInstrumentationTestCase2<EmptyActivity> EmptyActivity activity; Context mContext = null; ... @Before public void setUp() { activity = getActivity(); mContext = activity; } ... //tests to follow }что делают остальные?
можно получить из MockContext и вернуть например a MockResources on
getResources(), действительного ContentResolver ongetContentResolver()и т. д. Это позволяет, с некоторой болью, некоторые тесты.альтернативой является запуск например Robolectric который имитирует всю ОС Android. Это было бы для системные тесты: это намного медленнее работать.
расширение AndroidTestCase и вызов AndroidTestCase: getContext () отлично работает для меня, чтобы получить контекст и использовать его с SQLiteDatabase.
единственное неудобство заключается в том, что база данных, которую он создает и/или использует, будет такой же, как и в производственном приложении, поэтому вы, вероятно, захотите использовать другое имя файла для обоих
например.
public static final String NOTES_DB = "notestore.db"; public static final String DEBUG_NOTES_DB = "DEBUG_notestore.db";
сначала создайте тестовый класс под (androidTest).
теперь используйте следующий код:
public class YourDBTest extends InstrumentationTestCase { private DBContracts.DatabaseHelper db; private RenamingDelegatingContext context; @Override public void setUp() throws Exception { super.setUp(); context = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), "test_"); db = new DBContracts.DatabaseHelper(context); } @Override public void tearDown() throws Exception { db.close(); super.tearDown(); } @Test public void test1() throws Exception { // here is your context context = context; }}
альтернативное решение состоит в том, чтобы избежать использования
ApplicationTestCaseилиAndroidTestCaseили любой другой класс, который зависит отContext. Дело в том, что нет необходимости тестироватьSQLiteилиORMрамки, так что вы можете создать интерфейс с basicCRUDметоды:public interface UsersManager{ User createUser(String userId); User getUser(String userId); boolean updateUser(User user); boolean deleteUser(User user); }и реализовать две версии: одна для тестов, а другой для производственной среды. Версия для тестов может быть легко реализована с помощью
HashMap:public class TestUsersManager implements UsersManager{ private HashMap<String, User> users = new HashMap(); public User createUser(String userId){ User result = new User(userId); users.put(userId, user); return result; } //... other methods }он работает быстро (нет диска
IOв случаеSQLite) и не имеет внешних зависимостей. Кстати, это тоже дополнительный уровень абстракции: для производственного кода Вы можете легко переключаться междуORMфреймворки, например.