Как читать вывод тестов в Java

Чтобы вам было проще разобраться в выводе тестов, в первую очередь объясним, как работают тесты на платформе.

Тестирование кода на Java происходит с помощью фреймворка JUnit, сами тесты также написаны на языке Java. Проверка кода запускается автоматически после нажатия на кнопку «Проверить». Тестируемая программа компилируется и проверяется с разными входными данными. При этом тесты следят, чтобы поведение программы соответствовало ожиданиям.

Когда тесты завершатся, на вкладке OUTPUT появится результат проверки. Если на этом этапе возникла ошибка, нужно прочитать вывод тестов. Этот вывод — наш главный помощник в отладке кода.

Виды ошибок

Никто не пишет код идеально. Поэтому рано или поздно вы столкнетесь с ошибками. Ошибки при выполнении упражнения можно условно разделить на три вида:

  • Ошибки компиляции — это синтаксические ошибки, которые возникают еще на этапе компиляции программы
  • Ошибки времени исполнения – такие ошибки не мешают компиляции, но препятствуют выполнению программы
  • Ошибки утверждений — ошибки, вызванные тестами. Они возникают, если результат работы функции не соответствует ожидаемому результату

Ошибки компиляции

Как видно из названия, такие ошибки возникают еще на этапе компиляции и препятствуют успешному компилированию кода. Они возникают из-за различного рода ошибок в самом тексте кода.

Например, к этому типу ошибок относятся:

  • Синтаксическая ошибка — пропущенная точка с запятой, незакрытая скобка
  • Обращение к несуществующей переменной
  • Использование неправильных типов данных

Если программа на Java написана синтаксически некорректно, то компилятор выводит на экран сообщение об ошибке.

Это сообщение выглядит так:

App.java:6: error: ';' expected

        System.out.println("aaa")

                                 ^

Сообщение об ошибке содержит:

  • Описание ошибки
  • Указание на файл, в котором произошла ошибка
  • Строчку в файле, где произошла ошибка

Ошибки времени выполнения

Эти ошибки не препятствуют компиляции, но при этом программа не работает так, как ожидается.

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

В Java существует огромное количество исключений, но знать их все не обязательно. Обычно название вызванного исключения и сообщение об ошибке понятно объясняют, в чем проблема.

Например, при делении числа на ноль возникнет исключение ArithmeticException и сообщение, что на ноль в Java делить нельзя.

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

Exception in thread "main" java.lang.ArithmeticException: / by zero

        at io.hexlet.App.sayHurrayThreeTimes(App.java:7)

Не стоит бояться исключений: достаточно прочитать его сообщение и станет понятно, что хочет Java.

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

Ошибки утверждений

Такие ошибки возникают, если результат работы функции не соответствует тому результату, который мы ожидали.

Для начала разберемся, как выглядят тесты для упражнений:

public class AppTest {

    @Test

    public void testTruncate() {

        var actual1 = App.truncate("hexlet", 3);

        assertThat(actual1).isEqualTo("hex...");




        var actual2 = App.truncate("Hello, world!", 5);

        assertThat(actual2).isEqualTo("Hello...");

    }

}


Тестируемый метод вызывается в тестах с определенными параметрами. Результат работы этого метода сравнивается с заранее определенным ожидаемым результатом.

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

Но если значения не совпадают, возникает ошибка AssertionFailedError.

Рассмотрим подробнее вывод на вкладке OUTPUT в случае падения тестов:

╷

├─ JUnit Jupiter ✔

│  └─ AppTest ✔

│     └─ testTruncate() ✘ 

│              expected: "hex..."

│               but was: "hexl..."

└─ JUnit Vintage ✔


Здесь мы видим:

  • Имя класса с тестами — AppTest
  • Имя самого теста, который не прошел — testTruncate()
  • Ожидаемый результат работы — в строчке expected
  • Фактический результат работы кода — в строчке but was

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

Отладка кода

Иногда с первого взгляда невозможно понять, чем вызвано неправильное поведение кода. Тогда на помощь приходит отладка — возможность заглянуть в процесс выполнения кода.

Существует несколько способов, но мы рассмотрим самый простой и распространенный — отладочную печать.

Отладочная печать — это вывод на экран значений переменных, вызовов функций, сообщений о выполнении итерации цикла в процессе работы программы.

Для этого достаточно добавить вызов метода System.out.println() с интересующим нас значением:

  var searchedChar = ch;

    System.out.println("Searched char " + searchedChar);

    while (i < str.length()) {

        var currentChar = str.charAt(i);

        System.out.println("Current char: " + currentChar);

        if (currentChar == searchedChar) {

            count = count + 1;

            System.out.println("count: " + count);

        }

            i = i + 1;

    }

Затем нужно запустить проверку тестами еще раз, чтобы на вкладке OUTPUT увидеть результат работы нашей отладочной печати:

Searched char A

Current char: A

count: 1

Current char: b

Current char: h

Current char: A

count: 2

Current char: k

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