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.


4
Метод fail () и методы assertX () на самом деле просто вызывают ошибку AssertionError, что приводит к некорректному завершению работы тестового метода. Вот почему успешное возвращение означает успех ...
Стивен Шланскер

-1 - метод pass () ничего не делает - он сразу выходит из теста без исключений. Это было бы эффективно эквивалентно оператору return в большинстве случаев (за исключением ожидаемых исключений, тайм-аутов и т. Д.).
topchef

1
@grigory: Вы правы, что pass()метод не может просто ничего не делать, иначе тест может не сработать после его вызова. Я удалил это предложение.
ColinD

Я не могу вас отблагодарить, помог мне избавиться от множества разочарований!
N00b Pr0grammer

71

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


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();
}

Как вы сказали, «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()бы не имело никакого смысла, потому что ничего не делало.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.