Какая разница между getTargetContext() и getContext (на InstrumentationRegistry)?
Я использую новую библиотеку поддержки тестирования Android (com.android.support.test:runner:0.2
) для запуска контрольных тестов
(a.k.a Тесты устройств или эмуляторов).
Я комментирую свой тестовый класс с помощью @RunWith(AndroidJUnit4.class)
и использую Android Studio для их запуска.
Для моих тестовых случаев мне нужен экземпляр Context
. Я могу получить его с помощью InstrumentationRegistry
, но он имеет два связанных с контекстом методов, и неясно, в чем разница.
В чем разница между InstrumentationRegistry.getContext()
и InstrumentationRegistry.getTargetContext()
?
Ответы
Ответ 1
InstrumentationRegistry
- это открытый экземпляр реестра, который содержит ссылку на инструментарий, запущенный в процессе, и аргументирует его, а также позволяет внедрять следующие экземпляры:
-
InstrumentationRegistry.getInstrumentation()
, возвращает инструмент, работающий в данный момент. -
InstrumentationRegistry.getContext()
, возвращает контекст этого пакета инструментария. -
InstrumentationRegistry.getTargetContext()
, возвращает контекст приложения целевого приложения. -
InstrumentationRegistry.getArguments()
, возвращает копию аргумента Bundle, который был передан в эту Инструментацию. Это полезно, когда вы хотите получить доступ к аргументам командной строки, переданным в Instrumentation для вашего теста.
РЕДАКТИРОВАТЬ:
Так, когда использовать getContext() против getTargetContext()?
Документация не делает большую работу по объяснению различий, так что вот от моего POV:
Вы знаете, что когда вы проводите тестирование на Android, у вас есть два приложения:
- Тестовое приложение, которое выполняет вашу тестовую логику и тестирует ваше "настоящее" приложение
- "Настоящее" приложение (которое увидят ваши пользователи)
Поэтому, когда вы пишете свои тесты и хотите загрузить ресурс вашего реального приложения, используйте getTargetContext()
.
Если вы хотите использовать ресурс вашего тестового приложения (например, тестовый ввод для одного из ваших тестов), тогда вызовите getContext()
.
Ответ 2
Вам может понадобиться InstrumentationRegistry.getContext()
для доступа к исходным ресурсам тестового примера.
Например, для доступа к app/src/androidTest/res/raw/resource_name.json
в TestCase:
final Context context = InstrumentationRegistry.getContext();
InputStream is = context.getResources().openRawResource(com.example.package.test.R.raw.resource_name);
Ответ 3
Мне потребовались часы, чтобы выяснить это.
У случая InstrumentedTest был элемент контекста, который был установлен в настройке следующим образом:
context = InstrumentationRegistry.getTargetContext();
это использовалось для открытия файлов, особенно таких вещей:
String filenameOriginal = context.getCacheDir() + "/initial.csv";
Теперь я решил, что мне нужно использовать какой-то ресурс, который доступен только в инструментальном тесте, я не хотел распространять этот ресурс вместе с версией выпуска. Поэтому я воссоздал тестируемые каталоги ресурсов:
app\src\androidTest
└───res
└───raw
v1.csv
Но чтобы использовать это в коде, я должен был вызвать что-то вроде этого:
public static Uri resourceToUri(Context context, int resID)
{
return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
context.getResources().getResourcePackageName(resID) + '/' +
context.getResources().getResourceTypeName(resID) + '/' +
context.getResources().getResourceEntryName(resID));
}
resourceToUri(context, R.raw.v1)
Что всегда было бы неудачно, потому что R.raw.v1 совпадал с чем-то, что было на самом деле в моем файле ресурсов R
из основного приложения. При использовании ресурсов в инструментальных тестах было создано два R
файла. Чтобы исправить это, я должен был включить тестовый файл R:
import com.my_thing.app.my_app.test.R;
однако вызов resourceToUri
таком случае завершится неудачно.
Проблема заключалась в том, что я должен был использовать не InstrumentationRegistry.getTargetContext()
а скорее InstrumentationRegistry.getInstrumentation().getContext()
чтобы получить ресурс R.raw.v1
поэтому я слепо заменяю настройку контекста для всего тестового класса. в
context = InstrumentationRegistry.getInstrumentation().getContext();
Это работало хорошо для конкретного теста, но другие тесты в тестовом примере начали терпеть неудачу с отказом в разрешении для имени filenameOriginal
я использовал выше.
Оказалось, что, заменив контекст на контекст инструментария, я получил путь, к которому мое приложение не имело доступа, и я получил FileNotFoundException
с permission denied
и GrantTestRule
или другие вещи не будут работать.
Так что будьте осторожны при использовании этих контекстов, это может затратить ваше время:/