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методу.
Рендалл Вітмен,

Відповіді:


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

Здається справді найбільш простим і корисним способом закінчити тест.
Бендж,

7

Я думаю, що на це питання потрібна оновлена ​​відповідь, оскільки більшість відповідей тут досить застарілі.

Перш за все до питання ОП:

Я думаю, що досить добре прийнято, що введення в 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();
}

Як ви сказали, "діяти" не робить нічого конкретного, тому ми все ще не знаємо, що саме створює виняток, незалежно від того, чи очікуємо це лінії. У цьому випадку приклад досить просто перевірити та перевірити, але уявіть, що ваш тест включає метод Utility, який використовує вкладені методи перед поверненням результату. Досі неможливо отримати джерело проблеми, якщо IDE не вкаже сайт винятків
Farid

4

Я також шукав passметод для JUnit, щоб я міг закоротити деякі тести, які не застосовувались у деяких сценаріях (існують інтеграційні тести, а не чисті модульні тести). Так шкода, що його там немає.

На щастя, є спосіб умовно проігнорувати тест, що насправді навіть краще підходить у моєму випадку за допомогою assumeTrueметоду:

Assume.assumeTrue (isTestAppvable);

Отже, тут тест буде виконаний, лише якщо isTestAppvable має значення true, інакше тест буде проігноровано.


2

Немає необхідності в методі проходження, тому що, коли з тестового коду не викидається AssertionFailedException, тестовий випадок модуля пройде.

Метод fail () насправді викидає AssertionFailedException, щоб провалити testCase, якщо контроль доходить до цієї точки.


Я думаю, що це насправді junit.framework.AssertionFailedError.
Кайл

А як щодо випадків помилок. скажімо, я отримую елемент, не видно виняток з webdriver.
sasikumar

1

Я думаю, що це питання є результатом невеликого нерозуміння процесу виконання тесту. У JUnit (та інших інструментах тестування) результати враховуються за методом, а не за викликом затвердження. Немає лічильника, який би відстежував, скільки 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.