Как доказать ошибку в этом куске кода с помощью модульного теста - PullRequest
2 голосов
/ 15 марта 2011

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

  1. Напишите модульный тест, который явно не проходит, показывая, что ошибка существует
  2. Исправить ошибку
  3. Перезапустите тест, чтобы убедиться, что ошибка исправлена ​​
  4. Зафиксируйте исправление и тест, чтобы избежать регрессий в будущем

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

public final class SomeClass {
    ...
    public void someMethod(Parameter param) {
        try {
            if (param.getFieldValue("fieldName").equals("true")) { // Causes NullPointerException
                ...
            }
        } catch (Exception ex) {
            log.warn("Troubles ...", ex);
        }
    }
}

Проблема в том, что fieldName не является обязательным, поэтому, если его нет, вы получаете NPE. Очевидное исправление:

if ("true".equals(param.getFieldValue("fieldName"))) {
    ...
}

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

Вы можете подумать, что делает метод? Я могу проверить эффект, который имеет метод. К сожалению, он связывается с какой-то удаленной системой, поэтому для этого потребуется огромный интеграционный тест, который кажется излишним с такой маленькой и простой ошибкой.

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

Ответы [ 7 ]

2 голосов
/ 15 марта 2011

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

2 голосов
/ 15 марта 2011

Вы можете сделать несколько вещей:

  1. Заглушить регистратор и проверить, регистрировалась ли ошибка или нет как индикатор того, произошла ли ошибка.Вы можете использовать TypeMock или Moles, если регистратор не может быть легко заменен.
  2. Измените часть внутри блока try на собственный метод и вызовите только этот метод внутри блока try, чтобы ваш модульный тест также вызывалметод.Теперь исключение не будет регистрироваться в режиме без вывода сообщений, и вы можете проверить, было ли оно выброшено.
0 голосов
/ 15 марта 2011

Возможно, вы решите использовать Boolean.toBoolean (String) или «true» .equalsIgnoreCase (text)

Если вы не хотите использовать это поведение, вы можете добавить тест, который показывает, что «True» и«ИСТИНА» рассматриваются как ложные.

0 голосов
/ 15 марта 2011

Добавьте дополнительного приложения-регистратора на уровне предупреждения для этого класса / регистратора в начале теста (и удалите его в конце).

Затем запустите someMethod и убедитесь, что новый приложениевсе еще пустой (тогда не было исключений) или имеет содержимое (тогда было исключение).

0 голосов
/ 15 марта 2011

Что ж, метод вашей компании действительно означает, что вам иногда приходится писать множество дополнительных тестов, и вы могли бы поспорить, если это путь к этой "очевидной простой ошибке".Но вы делаете это по причине.

Я бы посмотрел на это так:

  • Ваш метод должен иметь определенный эффект.
  • Он делаетне имеют этого эффекта в данный момент.
  • Если вы хотите исправить это и проверить, работает ли метод, вам нужно проверить эффект.

Следовательно, вы, вероятно, должны написатьвесь код, даже с внешними системами, для проверки работоспособности функции.Или в этом случае нет.

0 голосов
/ 15 марта 2011

log может быть внедренным сервисом, что означает, что SomeClass выглядит так:

public final class SomeClass 
{
    private final Logger log;

    public SomeClass(Logger log)
    {
        this.log = log;
    }
}

Таким образом, в вашем модульном тесте вы могли пройти поддельный Logger (возможно, построенный с насмешливой структурой ), который позволяет вам определить, было ли зарегистрировано предупреждение во время теста.

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

Еще один вариант - добавить Handler к log в модульном тесте с целью обнаружения warn вызовов (при условии, что вы используете java.util.logging.Logger , но, похоже, это не так, потому что метод предупреждение , а не warn).

0 голосов
/ 15 марта 2011

ИМХО любой подвох все не так. Вы хотите поймать конкретные исключения, которые вы ищете. Юнит-тестирование - это также улучшение кода, поэтому вы можете изменить его на

catch (ExpectedException ex)
...