Как сделать, JUnit утверждает на сообщении в регистраторе

Шаблоны URL являются массивом, поэтому вам нужно передать URL как элемент массива. Пример: -

urlpatterns = [url(), url(), url()]
176
задан approxiblue 10 July 2016 в 05:19
поделиться

7 ответов

Большое спасибо за эти (на удивление) быстрые и полезные ответы; они направили меня на правильный путь к моему решению.

Кодовая база, в которой я хочу это использовать, использует java.util.logging в качестве механизма регистрации, и я не чувствую себя достаточно хорошо в этих кодах, чтобы полностью изменить это к log4j или к интерфейсам / фасадам регистратора. Но, основываясь на этих предложениях, я «взломал» расширение julhandler, и это работает как удовольствие.

Ниже следует краткое резюме. Extend java.util.logging.Handler :

class LogHandler extends Handler
{
    Level lastLevel = Level.FINEST;

    public Level  checkLevel() {
        return lastLevel;
    }    

    public void publish(LogRecord record) {
        lastLevel = record.getLevel();
    }

    public void close(){}
    public void flush(){}
}

Очевидно, что вы можете хранить столько, сколько хотите / хотите / нужно из LogRecord , или помещать их все в стек, пока вы получите переполнение.

При подготовке к junit-test вы создаете java.util.logging.Logger и добавляете к нему такой новый LogHandler :

@Test tester() {
    Logger logger = Logger.getLogger("my junit-test logger");
    LogHandler handler = new LogHandler();
    handler.setLevel(Level.ALL);
    logger.setUseParentHandlers(false);
    logger.addHandler(handler);
    logger.setLevel(Level.ALL);

Вызов setUseParentHandlers () предназначен для отключения обычных обработчиков, чтобы (для этого запуска junit-test) не происходило ненужного ведения журнала. Сделайте все, что нужно вашему тестируемому коду, чтобы использовать этот регистратор, запустите тест и assertEquality:

    libraryUnderTest.setLogger(logger);
    methodUnderTest(true);  // see original question.
    assertEquals("Log level as expected?", Level.INFO, handler.checkLevel() );
}

(Конечно, вы бы переместили большую часть этой работы в метод @Before и сделали другие улучшения, но это загромождает эту презентацию.)

34
ответ дан 23 November 2019 в 20:23
поделиться
Here is the sample code to mock log, irrespective of the version used for junit or sping, springboot.

import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.Appender;
import org.mockito.ArgumentMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.junit.Test;

import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class MyTest {
  private static Logger logger = LoggerFactory.getLogger(MyTest.class);

    @Test
    public void testSomething() {
    ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
    final Appender mockAppender = mock(Appender.class);
    when(mockAppender.getName()).thenReturn("MOCK");
    root.addAppender(mockAppender);

    //... do whatever you need to trigger the log

    verify(mockAppender).doAppend(argThat(new ArgumentMatcher() {
      @Override
      public boolean matches(final Object argument) {
        return ((LoggingEvent)argument).getFormattedMessage().contains("Hey this is the message I want to see");
      }
    }));
  }
}
2
ответ дан 23 November 2019 в 20:23
поделиться

Я ответил на подобный вопрос для log4j, видят how-can-i-test-with-junit-that-a-warning-was-logged-with-log4

, Это является более новым и пример с Log4j2 (протестированный с 2.11.2) и junit 5;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.*;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.hamcrest.core.Is;
import org.junit.Assert;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;

class TestLogger {

    private TestAppender testAppender;
    private LoggerConfig loggerConfig;
    private final Logger logger = (Logger) 
    LogManager.getLogger(ClassUnderTest.class);

    @Test
    @DisplayName("Test Log Junit5 and log4j2")
    void test() {
        ClassUnderTest.logMessage();
        final LogEvent loggingEvent = testAppender.events.get(0);
        //asset equals 1 because log level is info, change it to debug and
        //the test will fail
        assertTrue("Unexpected empty log",testAppender.events.size()==1);
        assertEquals("Unexpected log level",Level.INFO,loggingEvent.getLevel());
        assertEquals("Unexpected log message"
                ,loggingEvent.getMessage().toString()
                ,"Hello Test");
    }

    @BeforeEach
    private void setup() {
        testAppender = new TestAppender("test", null);

        final LoggerContext context = logger.getContext();
        final Configuration configuration = context.getConfiguration();

        loggerConfig = configuration.getLoggerConfig(logger.getName());
        loggerConfig.setLevel(Level.INFO);
        loggerConfig.addAppender(testAppender,Level.INFO,null);
        testAppender.start();
        context.updateLoggers();
    }

    @AfterEach
    void after(){
      logAppender.stop();
      loggerConfig.removeAppender("TestAppender");
      final LoggerContext context = logger.getContext();
      context.updateLoggers();
    }

    @Plugin( name = "TestAppender", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE)
    static class TestAppender extends AbstractAppender {

        List<LogEvent> events = new ArrayList();

        protected TestAppender(String name, Filter filter) {
            super(name, filter, null);
        }

        @PluginFactory
        public static TestAppender createAppender(
                @PluginAttribute("name") String name,
                @PluginElement("Filter") Filter filter) {
            return new TestAppender(name, filter);
        }

        @Override
        public void append(LogEvent event) {
            events.add(event);
        }
    }

     static class ClassUnderTest {
        private static final Logger LOGGER =  (Logger) LogManager.getLogger(ClassUnderTest.class);
        public static void logMessage(){
            LOGGER.info("Hello Test");
            LOGGER.debug("Hello Test");
        }
    }
}
0
ответ дан 23 November 2019 в 20:23
поделиться

Mocking - это вариант, хотя это было бы сложно, потому что логгеры обычно являются закрытыми статическими final - поэтому установка фиктивного логгера не будет делом торта, либо потребуется модификация тестируемого класса.

Вы можете создать собственный Appender (или как он там называется) и зарегистрировать его - либо через тестовый файл конфигурации, либо через среду выполнения (в некотором роде, в зависимости от на каркасе регистрации). Затем вы можете получить это приложение (статически, если оно объявлено в файле конфигурации, или по его текущей ссылке, если вы подключаете его во время выполнения) и проверить его содержимое.

10
ответ дан 23 November 2019 в 20:23
поделиться

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

logger.info ()

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

15
ответ дан 23 November 2019 в 20:23
поделиться

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

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

Я бы сделал что-то вроде этого:

class FakeLogger implements ILogger {
    public List<String> infos = new ArrayList<String>();
    public List<String> errors = new ArrayList<String>();

    public void info(String message) {
        infos.add(message);
    }

    public void error(String message) {
        errors.add(message);
    }
}

class TestMyClass {
    private MyClass myClass;        
    private FakeLogger logger;        

    @Before
    public void setUp() throws Exception {
        myClass = new MyClass();
        logger = new FakeLogger();
        myClass.logger = logger;
    }

    @Test
    public void testMyMethod() {
        myClass.myMethod(true);

        assertEquals(1, logger.infos.size());
    }
}
4
ответ дан 23 November 2019 в 20:23
поделиться

Мне это тоже нужно было несколько раз. Ниже я собрал небольшой образец, который вы хотите приспособить к своим потребностям. По сути, вы создаете свой собственный Appender и добавляете его в желаемый регистратор. Если вы хотите собрать все, корневое средство ведения журнала - хорошее место для начала, но вы можете использовать более конкретный, если хотите. Не забудьте удалить Appender, когда закончите, иначе вы можете создать утечку памяти. Ниже я сделал это в рамках теста, но setUp или @Before и tearDown или @After могут быть лучше, в зависимости от ваших потребностей.

Кроме того, реализация ниже собирает все в List в памяти. Если вы много ведете журнал, вы можете подумать о добавлении фильтра, чтобы удалить скучные записи или записать журнал во временный файл на диске (Подсказка: LoggingEvent is Serializable , поэтому вы должен иметь возможность просто сериализовать объекты событий, если ваше сообщение журнала.)

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

public class MyTest {
    @Test
    public void test() {
        final TestAppender appender = new TestAppender();
        final Logger logger = Logger.getRootLogger();
        logger.addAppender(appender);
        try {
            Logger.getLogger(MyTest.class).info("Test");
        }
        finally {
            logger.removeAppender(appender);
        }

        final List<LoggingEvent> log = appender.getLog();
        final LoggingEvent firstLogEntry = log.get(0);
        assertThat(firstLogEntry.getLevel(), is(Level.INFO));
        assertThat((String) firstLogEntry.getMessage(), is("Test"));
        assertThat(firstLogEntry.getLoggerName(), is("MyTest"));
    }
}

class TestAppender extends AppenderSkeleton {
    private final List<LoggingEvent> log = new ArrayList<LoggingEvent>();

    @Override
    public boolean requiresLayout() {
        return false;
    }

    @Override
    protected void append(final LoggingEvent loggingEvent) {
        log.add(loggingEvent);
    }

    @Override
    public void close() {
    }

    public List<LoggingEvent> getLog() {
        return new ArrayList<LoggingEvent>(log);
    }
}
136
ответ дан 23 November 2019 в 20:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: