#android #testing #junit
#Android #тестирование #junit
Вопрос:
Я пытаюсь написать несколько тестов, используя встроенную платформу тестирования Android Junit. Я столкнулся с проблемой с тестом, в котором я ожидаю, что будет выдано исключение. В JUnit аннотация для метода тестирования будет:
@Test(expected = ArithmeticException.class)
Однако в Android этот тест завершается с ошибкой ArithmeticException.
Я понимаю, что реализация Android является лишь подмножеством JUnit 3 и даже не допускает аннотацию @Test (должна быть @SmallTest, @MediumTest или @LargeTest, и ни один из них не допускает параметр ‘expected = ..’), но это кажется довольно значительным тестом, и похоже, что фреймворку тестирования Android серьезно не хватало бы, если бы у него не было этой функции.
Примечание: Я протестировал это, добавив JUnit jar в проект и добавив аннотации к моим методам тестирования. Для меня имеет смысл, почему аннотации будут полностью проигнорированы, потому что платформа Android (runner?) не ищет эту аннотацию и просто игнорирует ее. В принципе, я просто ищу «правильный» способ сделать это в рамках фреймворка.
Ответ №1:
Стандартная идиома junit 3 для такого рода тестов была:
public void testThatMethodThrowsException()
{
try
{
doSomethingThatShouldThrow();
Assert.fail("Should have thrown Arithmetic exception");
}
catch(ArithmeticException e)
{
//success
}
}
Комментарии:
1. Эта идиома также работает в JUnit4, когда вы хотите проверить состояние чего-либо после возникновения исключения. Вы не можете ничего утверждать при использовании «ожидаемой» идиомы после возникновения исключения.
2. Вы должны отменить пометку этого ответа как правильного и проверить ответ sandrstar, который является лучшим способом.
Ответ №2:
Теперь JUnit4 доступен через Android SDK (см. android-test-kit)
Обновление: теперь оно официально на d.android.com:
AndroidJUnitRunner — это новый разделенный тестовый раннер для Android, который является частью библиотеки тестов поддержки Android и может быть загружен через репозиторий поддержки Android. Новый раннер содержит все улучшения GoogleInstrumentationTestRunner и добавляет больше функций:
- Поддержка JUnit4
- Реестр инструментария для доступа к инструментам, контексту и аргументам пакета
- Тестовые фильтры @SdkSupress и @RequiresDevice
- Тайм-ауты тестирования
- Сегментирование тестов
- Поддержка RunListener для подключения к жизненному циклу тестового запуска
- Механизм мониторинга активности ActivityLifecycleMonitorRegistry
Итак, тестирование исключений в стиле JUnit4 с использованием ожидаемой аннотации:
@Test(expected= IndexOutOfBoundsException.class)
public void empty() {
new ArrayList<Object>().get(0);
}
или ожидаемые правила исключения:
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void shouldTestExceptionMessage() throws IndexOutOfBoundsException {
List<Object> list = new ArrayList<Object>();
thrown.expect(IndexOutOfBoundsException.class);
thrown.expectMessage("Index: 0, Size: 0");
list.get(0); // execution will never get past this line
}
также возможно.
Обратитесь к официальной документации для получения более подробной информации о том, как настроить библиотеку поддержки тестирования.
Комментарии:
1. Работает ли это у вас с модульными тестами? т. е. в тестовом каталоге проекта, а не в каталоге androidTest?
2. @Louth да, на самом деле я использую его в основном без gradle, и большую часть времени он работает нормально. Я не пробовал eclipse, но IntelliJ Idea подходит. Вы можете использовать maven или просто получить jar из вашего Android SDK (распакуйте aar из extras android m2repository com android support test testing-support-lib .1).
3. Да, приветствую @sandrstar. Это довольно старая тема, и да, при использовании Android Studio теперь все довольно просто. 🙂
Ответ №3:
Я искал несколько хороших решений, однако ни одно из решений меня по-настоящему не удовлетворило. Итак, я создал свой собственный.
public final void assertThrows(VoidFunction v, Class<? extends Exception> e) {
try {
v.call();
} catch (Exception ex) {
if (!ex.getClass().equals(e)) {
Assert.fail();
}
// Do nothing, basically succeeds test if same exception was thrown.
return;
}
// Fails if no exception is thrown by default.
Assert.fail();
}
Где VoidFunction — это простой интерфейс:
@FunctionalInterface
public interface VoidFunction {
void call();
}
Это используется следующим образом (например):
@Test
public void testFoo() {
assertThrows(() -> foo.bar(null)), NullPointerException.class);
assertThrows(() -> foo.setPositiveInt(-5)), IllegalArgumentException.class);
assertThrows(() -> foo.getObjectAt(-100)), IndexOutOfBoundsException.class);
assertThrows(new VoidFunction() {
@Override
public void call() {
foo.getObjectAt(-100);
}
}, IndexOutOfBoundsException.class); // Success
assertThrows(new VoidFunction() {
@Override
public void call() {
throw new Exception();
}
}, NullPointerException.class); // Fail
}
Я включил один вызов без использования лямбда-выражения, это иногда облегчает понимание кода, по крайней мере, для меня.
Простой в использовании и допускающий несколько перехватов исключений ОДНИМ методом.