Подтвердить что ты не робот

Тестирование устройств: регистрация и зависимость от инъекций

Итак, для ведения журнала с SO и других сайтов в Интернете лучший ответ кажется:

void DoSomething() {
    Logger.Log("Doing something!");
    // Code...
}

В общем случае вы избегаете статических методов, но в случае ведения журнала (частный случай) это самый простой и чистый маршрут. В статическом классе вы можете легко вставить экземпляр через конфигурационный файл/фреймворк, чтобы получить тот же эффект, что и DI.

Моя проблема связана с перспективой тестирования модулей.

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

Должен ли я писать unit test для ведения журнала (но использовать экземпляр mock для самого журнала)? Я знаю, если бы это было так, мне пришлось бы написать интеграционный тест, чтобы доказать, что регистратор фактически написал в файл журнала, но я не уверен.

После разработки, основанной на тестировании (что я делаю) мне понадобится unit test для того, чтобы диктовать интерфейс нет?

Любые советы?

4b9b3361

Ответ 1

Лично я довольно часто практикую TDD/BDD, и я почти никогда не тестирую журнал. За некоторыми исключениями регистрация является либо удобством разработчика, либо коэффициентом юзабилити, а не частью спецификации основного метода. Он также имеет тенденцию к намного более высокой скорости изменения, чем фактическая семантика метода, поэтому вы завершаете тесты, просто потому, что добавили еще несколько информационных протоколов.

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

Ответ 2

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

Сколько вы действительно хотите знать, работает ли ведение журнала, помимо того, что вы увидите через другие (практические) испытания? Возможно, вы захотите использовать DI для случайного класса, где ведение журнала действительно важно, но в противном случае я просто не стал бы тестировать протоколирование.

Это предполагает, что журнал имеет отладочную природу - если это журнал аудита или что-то в этом роде (что-то с функциональным требованием), то другое дело.

Ответ 3

Я разделил бы регистрацию на три категории:

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

2) Решение проблем. Если вы начнете получать странное состояние в QA или производстве, вы хотите отслеживать, что происходит. В общем, я бы сказал, что если это важно (скажем, в многопоточном приложении, где состояние может усложняться, но не может быть воспроизведено с помощью известных шагов), то тестирование того, что данные состояния в конечном итоге занесено в журнал, может быть ценным (так что вы aren 't проверяя всю читаемость журнала, только что некоторые факты попадают туда). Даже если класс будет изменен позже, это состояние по-прежнему будет регистрироваться (вместе с дополнительным состоянием), поэтому связь между тестом и протоколированием является разумной. Таким образом, в этом случае проверяются только те части журнала (a содержит тест).

3) Помощь по развитию. Во многих случаях я использую протоколирование как более надежную форму комментариев. Вы можете написать выражение вроде:

 logger.debug("Extract the fifth instance of BLAH from the string " + s);

Чтобы вы могли документировать код и в то же время иметь полезный артефакт, если вам когда-либо нужно отлаживать то, что происходит. В этом случае я вообще не был бы unit test, так как существование или нет данного утверждения не важно само по себе.

Что касается представления о том, что вам нужно проверить 100% всего, см. ответ Kent Beck здесь. Я думаю, что "проверить все" - это хороший совет для новичков, потому что, когда вы начинаете с TDD, соблазн будет состоять в том, чтобы не тестировать что-либо, что трудно проверить, или это заставляет вас задуматься о дизайне, чтобы сделать его проверяемым, и рационализировать его как несущественное. Но как только вы знаете, что делаете, и цените ценность тестов, тогда важно сбалансировать то, что вы делаете, с тем, что стоит проверить.

Ответ 4

Большинство фреймворков регистрации позволяют вам предоставлять пользовательскую реализацию для компонентов. Вы можете использовать этот механизм конфигурации для предоставления своих собственных реализаций.


Например, Java Log4J позволяет объявлять пользовательские appenders, которые являются компонентами, ответственными за "доставку" LoggingEvent.

Логгер можно легко высмеивать и вводить, используя:

Appender appenderMock = EasyMock.createMock(Appender.class);
/* expect */ appenderMock.doAppend(EasyMock.isA(LoggingEvent.class));
EasyMock.replay(appenderMock);

Logger.getLogger(/* replace with your own */"My logger").addAppender(appenderMock);

EasyMock.verify(appenderMock);

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

Ответ 5

Я бы сказал, что, вероятно, разумно написать Unit Test для ведения журнала; Я делал это раньше, и это оказалось более полезным, чем я предполагал. Как правило, ведение журналов Unit Testing дает вам хорошую уверенность в том, что средство ведения журнала работает со временем Unit Test, что может быть хорошей гарантией. Я не считаю критическим для журнала Unit Test, но если у вас есть склонность, я сомневаюсь, что это тоже будет плохо.

Ответ 6

Лично я думаю, что его overkill для unit test протоколирующих операторов. Но если вы действительно захотите это сделать, тогда будет работать mock logger или, если вы используете фреймворк вроде log4j, напишите пользовательский appender, который используется во время тестовых прогонов.

Ответ 7

Я обычно не unit test протоколирует заявления, утверждая, что записано, но я проверяю, что пути кода, принятые моими модульными тестами, охватывают протоколирование только для того, чтобы убедиться, что я не получаю исключение при регистрации исключения!

Ответ 8

У меня, вероятно, будет отдельный блок модульных тестов для самого регистратора, чтобы проверить его различные функции отдельно от всего остального. В методах, использующих регистратор, я просто проверю, что был вызван журнал (т.е. Ожидал, что он был вызван) с правильными параметрами. Например, если у меня есть метод:

DoSomething()
{
    if (FatalErrorOccurred)
    {
        Logger.Log("Fatal Error", ErrorLevel.Fatal);
    }
}

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

Ответ 9

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

Например, в следующем коде есть ошибка, которая будет вызывать исключение FormatException, только если включена трассировка уровня Debug.

if (logger.IsDebugEnabled)
{
    string message = String.Format(CultureInfo.CurrentCulture, 
          "... {1} ...", someValue);
    logger.Debug(message);
}