Тестирование блоков Android, требующих контекста
Я пишу свой первый бэкэнд на базе Android, и я пытаюсь создать unit test создание моей базы данных.
В настоящее время проблема, с которой я сталкиваюсь, заключается в получении действительного объекта Context для передачи моей реализации SQLiteOpenHelper. Есть ли способ получить объект Context в классе, расширяющем TestCase? Решение, о котором я думал, состоит в том, чтобы создать экземпляр Activity в методе настройки моей TestCase, а затем назначить контекст этого действия переменной поля, к которой могут обращаться мои методы тестирования... но похоже, что должен быть более простой способ.
Спасибо за ваш вклад!
Мэйси
Ответы
Ответ 1
Вы можете попробовать перейти на AndroidTestCase. От взгляда на документы, похоже, он должен предоставить вам действительный контекст для перехода к SQLiteOpenHelper.
Изменить:
Имейте в виду, что вам, вероятно, придется настроить свои тесты в "Android Test Project" в Eclipse, поскольку тесты будут пытаться выполнить на эмуляторе (или на реальном устройстве).
Ответ 2
Вы можете использовать методы InstrumentationRegistry
для получения контекста:
InstrumentationRegistry.getTargetContext()
- предоставляет Context
приложения целевого приложения.
InstrumentationRegistry.getContext()
- предоставляет Context
этого пакета Инструментов.
Для AndroidX используйте InstrumentationRegistry.getInstrumentation().getTargetContext()
или InstrumentationRegistry.getInstrumentation().getContext()
.
Ответ 3
Использование метода 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
}
Что делают все остальные?
Ответ 4
Вы должны использовать ApplicationTestCase или ServiceTestCase.
Ответ 5
Вы можете получить MockContext и вернуться, например, MockResources на getResources()
, действительный ContentResolver на getContentResolver()
и т.д. Это позволяет, с некоторой болью, некоторые модульные тесты.
Альтернативой является запуск, например, Robolectric, который имитирует целую ОС Android. Это будет для системных тестов: он намного медленнее запускать.
Ответ 6
Расширение AndroidTestCase и вызов AndroidTestCase: getContext() отлично работает для меня, чтобы получить контекст и использовать его с SQLiteDatabase.
Единственное, что создаёт и/или использует база данных, будет такой же, как та, что используется производственным приложением, поэтому вы, вероятно, захотите использовать другое имя файла для
например.
public static final String NOTES_DB = "notestore.db";
public static final String DEBUG_NOTES_DB = "DEBUG_notestore.db";
Ответ 7
Сначала создайте тестовый класс в (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;
}}
Ответ 8
Ваш тест не является модульным тестом !!!
Когда ты нуждаешься
- контекст
- Читать или писать на хранение
- Сеть доступа
- Или измените любой конфиг, чтобы проверить вашу функцию
Вы не пишите unit тест.
Вам нужно написать свой тест в пакете androidTest
Ответ 9
Альтернативное решение состоит в том, чтобы избежать использования ApplicationTestCase
или AndroidTestCase
или любого другого класса, который зависит от Context
. Дело в том, что нет необходимости тестировать структуру SQLite
или ORM
, чтобы вы могли создать интерфейс с помощью базовых методов CRUD
:
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
.