JUnit4 fail () здесь, но где pass ()?

85

В fail()библиотеке JUnit4 есть метод. Мне это нравится, но испытываю нехваткуpass() метода, которого нет в библиотеке. Почему это так?

Я обнаружил, что могу использовать assertTrue(true)вместо этого, но все равно выглядит нелогично.

@Test
 public void testSetterForeignWord(){
  try {
   card.setForeignWord("");
   fail();
  } catch (IncorrectArgumentForSetter ex){
  }

 // assertTrue(true);
 }
Евгений
источник
7
Просто используйте оператор return - в большинстве случаев он будет проходить как pass ().
topchef
@topchef этот единственный комментарий ударил по голове, в то время как все остальные спорили о том, что приемлемо, а что нет.
Некоторые тестовые системы (perl Test :: Simple) подсчитывают пройденные и неудачные утверждения. Однако Junit подсчитывает количество успешных и неудачных методов тестирования . Таким образом, у Junit нет такого же использования passметода.
Randall Whitman

Ответы:

65

Пока тест не генерирует исключение, он проходит, если в вашей @Testаннотации не указано ожидаемое исключение. Я полагаю, что a pass()может вызвать специальное исключение, которое JUnit всегда интерпретирует как прохождение, чтобы сократить тест, но это будет противоречить обычному дизайну тестов (т.е. предположить успех и только потерпеть неудачу, если утверждение не выполняется) и, если люди получили идея, которую было бы предпочтительнее использовать pass(), значительно замедлила бы прохождение большого набора тестов (из-за накладных расходов на создание исключений). Неудачные тесты не должны быть нормой, поэтому нет ничего страшного, если у них есть такие накладные расходы.

Обратите внимание, что ваш пример можно переписать так:

@Test(expected=IncorrectArgumentForSetter.class)
public void testSetterForeignWord("") throws Exception {
  card.setForeignWord("");
}

Кроме того, вы должны отдавать предпочтение использованию стандартных исключений Java. Вы IncorrectArgumentForSetterдолжны , вероятно , быть IllegalArgumentException.

ColinD
источник
4
Метод fail () и методы assertX () на самом деле просто вызывают ошибку AssertionError, что приводит к некорректному завершению работы тестового метода. Вот почему успешное возвращение означает успех ...
Стивен Шланскер
-1 - метод pass () ничего не делает - он сразу выходит из теста без исключений. Это было бы эффективно эквивалентно оператору return в большинстве случаев (за исключением ожидаемых исключений, тайм-аутов и т. Д.).
topchef
1
@grigory: Вы правы, что pass()метод не может просто ничего не делать, иначе тест может не сработать после его вызова. Я удалил это предложение.
ColinD
Я не могу вас отблагодарить, помог мне избавиться от множества разочарований!
N00b Pr0grammer
71

Вызовите returnоператор в любое время, когда ваш тест будет завершен и пройден.

Horcrux7
источник
3
+1 должен был быть правильный ответ (в большинстве случаев, за исключением ожидаемых, тайм-аутов и т. Д.)
topchef
Кажется, действительно, самый простой и удобный способ завершить тест.
Benj
7

Я думаю, что на этот вопрос нужен обновленный ответ, поскольку большинство ответов здесь довольно устарели.

Во-первых, на вопрос 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() {
    //setup
    AxisRange range = new AxisRange(0,100);

    //act
    Runnable act = () -> range.setLowerBound(200);

    //assert
    assertThrows(IllegalArgumentException.class, act);
}

эти тесты немного неудобны, потому что шаг «действие» на самом деле не выполняет никаких действий, но я думаю, что смысл все еще довольно ясен.

в maven также есть крошечная библиотека, называемая catch-exception, которая использует синтаксис в стиле mockito для проверки того, что исключения генерируются. Выглядит симпатично, но я не фанат динамических прокси. Тем не менее, синтаксис настолько хорош, что остается заманчивым:

// given: an empty list
List myList = new ArrayList();

// when: we try to get the first element of the list
// then: catch the exception if any is thrown 
catchException(myList).get(1);

// then: we expect an IndexOutOfBoundsException
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 {
    //this line will cause the test to be branded as "ignored" when "isCircleCI" 
    //(the machine running ubuntu is running this test) is true.
    Assume.assumeFalse(BootstrappingUtilities.isCircleCI());
    //an ignored test will typically result in some qualifier being put on the results, 
    //but will also not typically prevent a green-ton most platforms. 

    //setup
    URL url = DLLTestFixture.class.getResource("USERDLL.dll");
    String path = url.toURI().getPath();
    path = path.substring(0, path.lastIndexOf("/"));

    //act
    NativeLibrary.addSearchPath("USERDLL", path);
    Object dll = Native.loadLibrary("USERDLL", NativeCallbacks.EmptyInterface.class);

    //assert
    assertThat(dll).isNotNull();
}
Groostav
источник
Как вы сказали, «act» не делает ничего конкретного, поэтому мы до сих пор не знаем, что именно вызывает исключение, независимо от того, ожидаем ли мы эту строку или нет. В этом случае пример довольно просто протестировать и проверить, но представьте, что ваш тест включает метод Utility, который использует вложенные методы перед возвратом результата. По-прежнему нет способа
Фарид
4

Я также искал passметод для JUnit, чтобы я мог сократить некоторые тесты, которые не были применимы в некоторых сценариях (есть интеграционные тесты, а не чистые модульные тесты). Так что жаль, что его там нет.

К счастью, есть способ условно игнорировать тест, который в моем случае подходит даже лучше, используя assumeTrueметод:

Assume.assumeTrue (isTestApplicable);

Таким образом, здесь тест будет выполняться, только если isTestApplicable истинно, иначе тест будет проигнорирован.

Себастьян К.
источник
2

В методе передачи нет необходимости, потому что, когда из тестового кода не выбрасывается AssertionFailedException, модульный тестовый пример будет пройден.

Метод fail () фактически генерирует исключение AssertionFailedException, чтобы не выполнить testCase, если в этот момент доходит управление.

Аджай
источник
Я думаю, что на самом деле это junit.framework.AssertionFailedError.
Кайл
Что насчет случаев ошибок. скажем, я получаю элемент, который не отображается, исключение из webdriver. Должен ли я поймать исключение и вернуться.
sasikumar
1

Я думаю, что этот вопрос - результат небольшого непонимания процесса выполнения теста. В JUnit (и других инструментах тестирования) результаты подсчитываются для каждого метода, а не для каждого вызова assert. Нет счетчика, который отслеживает, сколько прошло / не assertXудалось выполнить.

JUnit выполняет каждый тестовый метод отдельно. Если метод завершился успешно, значит тест зарегистрирован как «пройден». Если возникает исключение, то тест регистрируется как «не пройденный». В последнем случае возможны два подслучая: 1) исключение утверждения JUnit, 2) исключения любого другого типа. В первом случае статус будет «сбой», а во втором - «ошибка».

В Assertклассе доступно множество сокращенных методов для выдачи исключений утверждений. Другими словами, Assertэто уровень абстракции над исключениями JUnit.

Например, это исходный код assertEqualsна GitHub :

/**
 * Asserts that two Strings are equal.
 */
static public void assertEquals(String message, String expected, String actual) {
    if (expected == null && actual == null) {
        return;
    }
    if (expected != null && expected.equals(actual)) {
        return;
    }
    String cleanMessage = message == null ? "" : message;
    throw new ComparisonFailure(cleanMessage, expected, actual);
}

Как видите, в случае равенства ничего не происходит, иначе будет выброшено исключение.

Так:

assertEqual("Oh!", "Some string", "Another string!");

просто генерирует ComparisonFailureисключение, которое будет перехвачено JUnit, и

assertEqual("Oh?", "Same string", "Same string");

ничего не делает.

В общем, что-то вроде pass()бы не имело никакого смысла, потому что ничего не делало.

Давид Хорват
источник