Я думаю, что на этот вопрос нужен обновленный ответ, поскольку большинство ответов здесь довольно устарели.
Во-первых, на вопрос OP:
Я думаю, что довольно хорошо принято, что введение концепции «ожидаемого исключения» в JUnit было плохим ходом, поскольку это исключение могло возникнуть где угодно, и оно пройдет проверку. Это работает, если вы генерируете (и утверждаете) очень специфичные для домена исключения, но я выбрасываю только такие исключения, когда я работаю над кодом, который должен быть абсолютно безупречным, - большинство APIS просто выбрасывает встроенные исключения, такие как IllegalArgumentException
или IllegalStateException
. Если два ваших вызова могут потенциально вызвать эти исключения, тогда @ExpectedException
аннотация будет зеленой полосой для вашего теста, даже если это неправильная строка, которая вызывает исключение!
Для этой ситуации я написал класс, который, я уверен, многие здесь написали, это assertThrows
метод:
public class Exceptions {
private Exceptions(){}
public static void assertThrows(Class<? extends Exception> expectedException, Runnable actionThatShouldThrow){
try{
actionThatShouldThrow.run();
fail("expected action to throw " + expectedException.getSimpleName() + " but it did not.");
}
catch(Exception e){
if ( ! expectedException.isInstance(e)) {
throw e;
}
}
}
}
этот метод просто возвращает, если возникает исключение, что позволяет вам выполнять дальнейшие утверждения / проверки в вашем тесте.
с синтаксисом java 8 ваш тест выглядит действительно красиво. Ниже приведен один из самых простых тестов нашей модели, в котором используется этот метод:
@Test
public void when_input_lower_bound_is_greater_than_upper_bound_axis_should_throw_illegal_arg() {
AxisRange range = new AxisRange(0,100);
Runnable act = () -> range.setLowerBound(200);
assertThrows(IllegalArgumentException.class, act);
}
эти тесты немного неудобны, потому что шаг «действие» на самом деле не выполняет никаких действий, но я думаю, что смысл все еще довольно ясен.
в maven также есть крошечная библиотека, называемая catch-exception, которая использует синтаксис в стиле mockito для проверки того, что исключения генерируются. Выглядит симпатично, но я не фанат динамических прокси. Тем не менее, синтаксис настолько хорош, что остается заманчивым:
List myList = new ArrayList();
catchException(myList).get(1);
assert caughtException() instanceof IndexOutOfBoundsException;
Наконец, для ситуации, с которой я столкнулся, чтобы добраться до этой темы, есть способ игнорировать тесты, если выполняется какое-то условие.
Прямо сейчас я работаю над вызовом некоторых DLL через библиотеку загрузки собственной библиотеки Java под названием JNA, но наш сервер сборки находится в ubuntu. Мне нравится управлять такого рода разработками с помощью тестов JUnit - даже если они на данный момент далеки от «единиц» -. Что я хочу сделать, так это запустить тест, если я нахожусь на локальной машине, но игнорировать тест, если мы на ubuntu. В JUnit 4 есть для этого положение, которое называется Assume
:
@Test
public void when_asking_JNA_to_load_a_dll() throws URISyntaxException {
Assume.assumeFalse(BootstrappingUtilities.isCircleCI());
URL url = DLLTestFixture.class.getResource("USERDLL.dll");
String path = url.toURI().getPath();
path = path.substring(0, path.lastIndexOf("/"));
NativeLibrary.addSearchPath("USERDLL", path);
Object dll = Native.loadLibrary("USERDLL", NativeCallbacks.EmptyInterface.class);
assertThat(dll).isNotNull();
}