Должны ли мы unit test регистрироваться? - программирование

Должны ли мы unit test регистрироваться?

Как правило, просмотр кода в коде

public class A {

private static final Log LOG = LogFactory.getLog(A.class);

и использование

        } catch (Exception e) {
           LOG.error(e.getMessage(), e);
           throw e;
        }

но я никогда не видел ни одного unit test для такого кода.

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

Предполагая, что я должен его покрыть, означает, что я должен изменить свой исходный код, чтобы ввести mock log, и проверить, что метод "error" был вызван с ожидаемым сообщением. Но что делать, если мой первоначальный класс является сервисом и он создается экземпляром spring, следует ли мне добавить какой-то журнал, а также другие зависимости?

4b9b3361

Ответ 1

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

Чтобы сделать код выше проверяемого, используйте инъекцию зависимостей. Это предполагает, что регистратор реализует интерфейс, ILog. Вы должны передать в журнал как параметр конструктора в класс A. Тогда тестовый код создаст макетную реализацию ILog и передаст это в конструктор. В приведенном выше коде не показано, как возникает исключение, но, предположительно, это будет через какой-то другой зависимый объект. Таким образом, вы тоже издеваетесь над этим, и заставляете его бросать исключение. Затем проверьте, что макет ILog вызвал метод error. Возможно, вы хотите изучить сообщение, которое оно регистрирует, но это может зайти слишком далеко, сделав тестовый код неустойчивым.

Ответ 2

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

Ответ 3

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

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

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

Есть два из них, которые приходят мне на ум прямо сейчас:

SLF4JTesting: не требует модификации конфигурации ведения журнала, но требует ввода журнала factory, который может привести к изменению кода.

Тест SLF4J: не такой мощный, как slf4jtesting и, похоже, не разработан, но хорошо работает с существующим кодом. Никаких изменений, кроме конфигурации регистратора для тестирования.

При использовании теста SLF4J утверждения достаточно строги и проверяют все событие на равенство. В этом случае интересным может быть пользовательский сопоставитель:

public static Matcher<LoggingEvent> errorMessageContains(final String s) {
    return new TypeSafeMatcher<LoggingEvent>() {
        @Override
        public void describeTo(final Description description) {
            description.appendText(" type " + Level.ERROR + " should contain ")
                    .appendValue(s);
        }

        @Override
        protected void describeMismatchSafely(final LoggingEvent item, final Description mismatchDescription) {
            mismatchDescription.appendText(" was type ").appendValue(l)
                    .appendText(" message ").appendValue(item.getMessage());
        }

        @Override
        protected boolean matchesSafely(final LoggingEvent item) {
            return item.getLevel().equals(Level.ERROR)
                    && item.getMessage().contains(s);
        }
    };
}

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

Ответ 4

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

Подробнее об этой теме: https://ardalis.com/logging-and-monitoring-are-requirements

Ответ 5

там другой способ: вы можете издеваться над LogFactory! например:

import junit.framework.Assert;
import mockit.Mock;
import mockit.MockUp;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;

public class XXXTest {
    class MyLog implements Log {
        public static final String INFO = "info";

        private String logLevel;
        private Object logContent;

        public String getLogLevel() {
            return logLevel;
        }

        public Object getLogContent() {
            return logContent;
        }

        @Override
        public void info(Object o) {
            logLevel = "info";
            logContent = o;
        }

        //Implement other methods
    }

    @Test
    public void testXXXFunction() {
        final MyLog log = new MyLog();
        new MockUp<LogFactory>() {
            @Mock
            public Log getLog(String name) {
                return log;
            }
        };

        //invoke function and log by MyLog
        FunctionToBeTest.invoke();
        Assert.assertEquals("expected log text", log.getLogContent());
    }
}

Удачи!