Captures log entries for unit testing purposes

Overview

Actions Status Quality Gate Status Coverage Reliability Rating Security Rating Vulnerabilities Apache2 license Maven Central javadoc FOSSA Status Join the chat at https://gitter.im/hakky54/logcaptor

SonarCloud

LogCaptor Tweet

Install with maven

<dependency>
    <groupId>io.github.hakky54</groupId>
    <artifactId>logcaptor</artifactId>
    <version>2.4.0</version>
    <scope>test</scope>
</dependency>

Introduction

LogCaptor is a library which will enable you to easily capture logging entries for unit testing purposes.

Tested Logging libraries

  • SLFJ4
  • Logback
  • Java Util Logging
  • Apache Log4j
  • Log4j with Lombok
  • Log4j2 with Lombok
  • SLFJ4 with Lombok
  • Java Util Logging with Lombok

See the unit test LogCaptorShould for all the scenario's or checkout this project Java Tutorials which contains more isolated examples of the individual logging frameworks

Supported Java versions

  • Java 8A
  • Java 11+

Usage

Basic example class
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class FooService {

    private static final Logger LOGGER = LogManager.getLogger(FooService.class);

    public void sayHello() {
        LOGGER.info("Keyboard not responding. Press any key to continue...");
        LOGGER.warn("Congratulations, you are pregnant!");
    }

}
Unit test:
import static org.assertj.core.api.Assertions.assertThat;

import nl.altindag.log.LogCaptor;
import org.junit.jupiter.api.Test;

public class FooServiceShould {

    @Test
    public void logInfoAndWarnMessages() {
        String expectedInfoMessage = "Keyboard not responding. Press any key to continue...";
        String expectedWarnMessage = "Congratulations, you are pregnant!";

        LogCaptor logCaptor = LogCaptor.forClass(FooService.class);

        FooService fooService = new FooService();
        fooService.sayHello();

        // Option 1 to assert logging entries
        assertThat(logCaptor.getInfoLogs()).containsExactly(expectedInfoMessage);
        assertThat(logCaptor.getWarnLogs()).containsExactly(expectedWarnMessage);

        // Option 2 to assert logging entries
        assertThat(logCaptor.getLogs())
                .hasSize(2)
                .containsExactly(expectedInfoMessage, expectedWarnMessage);
    }
}
Initialize LogCaptor once and reuse it during multiple tests with clearLogs method within the afterEach method:
import nl.altindag.log.LogCaptor;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.AfterEach;

public class FooServiceShould {

    private LogCaptor logCaptor = LogCaptor.forClass(FooService.class);
    private static final String EXPECTED_INFO_MESSAGE = "Keyboard not responding. Press any key to continue...";
    private static final String EXPECTED_WARN_MESSAGE = "Congratulations, you are pregnant!";

    @AfterEach
    public void clearLogs() {
        logCaptor.clearLogs();
    }

    @Test
    public void logInfoAndWarnMessagesAndGetWithEnum() {
        Service service = new FooService();
        service.sayHello();

        assertThat(logCaptor.getInfoLogs()).containsExactly(EXPECTED_INFO_MESSAGE);
        assertThat(logCaptor.getWarnLogs()).containsExactly(EXPECTED_WARN_MESSAGE);

        assertThat(logCaptor.getLogs()).hasSize(2);
    }

    @Test
    public void logInfoAndWarnMessagesAndGetWithString() {
        Service service = new FooService();
        service.sayHello();

        assertThat(logCaptor.getInfoLogs()).containsExactly(EXPECTED_INFO_MESSAGE);
        assertThat(logCaptor.getWarnLogs()).containsExactly(EXPECTED_WARN_MESSAGE);

        assertThat(logCaptor.getLogs()).hasSize(2);
    }

}
Class which will log events if specific log level has been set
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class FooService {

    private static final Logger LOGGER = LogManager.getLogger(FooService.class);

    public void sayHello() {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Keyboard not responding. Press any key to continue...");
        }
        LOGGER.info("Congratulations, you are pregnant!");
    }

}
Unit test:
import static org.assertj.core.api.Assertions.assertThat;

import nl.altindag.log.LogCaptor;
import org.junit.jupiter.api.Test;

public class FooServiceShould {

    @Test
    public void logInfoAndWarnMessages() {
        String expectedInfoMessage = "Congratulations, you are pregnant!";
        String expectedDebugMessage = "Keyboard not responding. Press any key to continue...";

        LogCaptor logCaptor = LogCaptor.forClass(FooService.class);
        logCaptor.setLogLevelToInfo();

        FooService fooService = new FooService();
        fooService.sayHello();

        assertThat(logCaptor.getInfoLogs()).containsExactly(expectedInfoMessage);
        assertThat(logCaptor.getDebugLogs())
            .doesNotContain(expectedDebugMessage)
            .isEmpty();
    }
}
Class which will also log an exception
import nl.altindag.log.service.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

public class FooService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ZooService.class);

    @Override
    public void sayHello() {
        try {
            tryToSpeak();
        } catch (IOException e) {
            LOGGER.error("Caught unexpected exception", e);
        }
    }

    private void tryToSpeak() throws IOException {
        throw new IOException("KABOOM!");
    }
}
Unit test:
import static org.assertj.core.api.Assertions.assertThat;

import nl.altindag.log.LogCaptor;
import nl.altindag.log.model.LogEvent;
import org.junit.jupiter.api.Test;

public class FooServiceShould {

    @Test
    void captureLoggingEventsContainingException() {
        LogCaptor logCaptor = LogCaptor.forClass(ZooService.class);

        Fervice service = new FooService();
        service.sayHello();

        List<LogEvent> logEvents = logCaptor.getLogEvents();
        assertThat(logEvents).hasSize(1);

        LogEvent logEvent = logEvents.get(0);
        assertThat(logEvent.getMessage()).isEqualTo("Caught unexpected exception");
        assertThat(logEvent.getLevel()).isEqualTo("ERROR");
        assertThat(logEvent.getThrowable()).isPresent();

        assertThat(logEvent.getThrowable().get())
                .hasMessage("KABOOM!")
                .isInstanceOf(IOException.class);
    }
}
Disable any logs for a specific class

In some use cases a unit test can generate too many logs by another class. This could be annoying as it will cause noise in your build logs. LogCaptor can disable those log messages with the following snippet:

import static org.assertj.core.api.Assertions.assertThat;

import nl.altindag.log.LogCaptor;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

public class FooServiceShould {

    private static LogCaptor logCaptorForSomeOtherService = LogCaptor.forClass(SomeService.class);

    @BeforeAll
    static void disableLogs() {
        logCaptorForSomeOtherService.disableLogs();
    }

    @AfterAll
    static void resetLogLevel() {
        logCaptorForSomeOtherService.resetLogLevel();
    }

    @Test
    void captureLoggingEventsContainingException() {
        String expectedInfoMessage = "Keyboard not responding. Press any key to continue...";
        String expectedWarnMessage = "Congratulations, you are pregnant!";

        LogCaptor logCaptor = LogCaptor.forClass(FooService.class);

        Fervice service = new FooService();
        service.sayHello();

        assertThat(logCaptor.getLogs())
                .hasSize(2)
                .containsExactly(expectedInfoMessage, expectedWarnMessage);
    }
}

Using Log Captor alongside with other logging libraries

When building your maven or gradle project it can complain that you are using multiple SLF4J implementations. Log Captor is using logback as SLF4J implementation and SLF4J doesn't allow you to use multiple implementations, therefor you need to explicitly specify which to use during which build phase. You can fix that by excluding your main logging framework during the unit/integration test phase. Below is an example for Maven Failsafe and Maven Surefire:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <classpathDependencyExcludes>
                    <classpathDependencyExclude>org.apache.logging.log4j:log4j-slf4j-impl</classpathDependencyExclude>
                </classpathDependencyExcludes>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <configuration>
                <classpathDependencyExcludes>
                    <classpathDependencyExclude>org.apache.logging.log4j:log4j-slf4j-impl</classpathDependencyExclude>
                </classpathDependencyExcludes>
            </configuration>
        </plugin>
    </plugins>
</build>

And for gradle:

configurations {
    testImplementation {
        exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j-impl'
    }
}

Contributing

There are plenty of ways to contribute to this project:

  • Give it a star
  • Share it with a Tweet
  • Join the Gitter room and leave a feedback or help with answering users questions
  • Submit a PR

License

FOSSA Status

Comments
  • org.apache.logging.log4j loggers not supported like test shows

    org.apache.logging.log4j loggers not supported like test shows

    I'm working with apache.logging.log4j on existing classes, and followed the example test as below.

    //Basic example class
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    public class FooService {
    
        private static final Logger LOGGER = LogManager.getLogger(FooService.class);
    
        public void sayHello() {
            LOGGER.info("Keyboard not responding. Press any key to continue...");
            LOGGER.warn("Congratulations, you are pregnant!");
        }
    
    }
    
    //Unit test:
    import nl.altindag.log.LogCaptor;
    
    public class FooServiceShould {
        @Test
        public void logInfoAndWarnMessages() {
            String expectedInfoMessage = "Keyboard not responding. Press any key to continue...";
            String expectedWarnMessage = "Congratulations, you are pregnant!";
    
            LogCaptor logCaptor = LogCaptor.forClass(FooService.class);
            //...
        }
    }
    

    However, i get the error shown below log4j-slf4j-impl cannot be present with log4j-to-slf4j using the same libraries as the demo.

    import org.apache.logging.log4j.Logger;
    import org.apache.logging.log4j.LogManager; //all existing classes are already setup with these libs
    
    public class Address {
        
        private static final Logger logger = LogManager.getLogger(Address.class);
        
        public Address(int a, int b, int c, int d) {
        	//other code
            logger.error("Address is malformed.");
        }
    }
    
    import nl.altindag.log.LogCaptor;
    
    public class AddressTest {
        @Test
        public void testAddressValidation() {
            LogCaptor logCaptor = LogCaptor.forClass(Address.class);
            
            new Address(999,0,0,0);
            
            assertTrue(logCaptor.getErrorLogs().contains("Address is malformed."));
        }
    }
    
    org.apache.logging.log4j.LoggingException: log4j-slf4j-impl cannot be present with log4j-to-slf4j
    	at org.apache.logging.slf4j.Log4jLoggerFactory.validateContext(Log4jLoggerFactory.java:49)
    	at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:39)
    	at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:30)
    	at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:54)
    	at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:30)
    	at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:363)
    	at nl.altindag.log.LogCaptor.<init>(LogCaptor.java:49)
    	at nl.altindag.log.LogCaptor.forClass(LogCaptor.java:69)
    	at ....AddressTest.testAddressValidation(AddressTest.java:20)
    

    and the console output

    SLF4J: Class path contains multiple SLF4J bindings.
    SLF4J: Found binding in [jar:file:~/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.13.3/log4j-slf4j-impl-2.13.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:~/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
    SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
    

    I'm not sure if i'm applying the pom exclusions properly, but it seems like it might be easier to make a version that is compatible with org.apache.logging.log4j instead

    opened by dereknheiley 15
  • configurations in log4j2.xml not being applied after installing logcaptor

    configurations in log4j2.xml not being applied after installing logcaptor

    In my log4j2.xml file I configured log messages to be printed without any log info, only the message itself () amd it was working fine. Once I added logcaptor dependency in my POM file, the log messages appear as if there is a default configuration, so my configuration won't be applied.

    opened by mhammadkassem 12
  • Does this project target Log4J API 1.7?

    Does this project target Log4J API 1.7?

    Describe the bug When putting log-captor to my project, I immediately get the classic org.apache.logging.log4j.LoggingException: log4j-slf4j-impl cannot be present with log4j-to-slf4j exception.

    BUT: excluding log4j-slf4j-impl from the test scope, turns thing around so that now NO logger implementation is found: SLF4J: No SLF4J providers were found. SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details. SLF4J: Class path contains SLF4J bindings targeting slf4j-api versions 1.7.x or earlier. SLF4J: Ignoring binding found at [jar:file:/Users/q163557/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-classic/1.2.11/4741689214e9d1e8408b206506cbe76d1c6a7d60/logback-classic-1.2.11.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See https://www.slf4j.org/codes.html#ignoredBindings for an explanation.

    SLF4J Logger implementation should be of the type [ch.qos.logback.classic.Logger] but found [org.slf4j.helpers.NOPLogger].

    My project is now working with Log4J2 - could it be that this log-captor is still using the 1.7 API??

    no-activity 
    opened by Zordid 9
  • Added information about capturing static inner classes, fixed javadoc warnings

    Added information about capturing static inner classes, fixed javadoc warnings

    Hello!

    Originally I've found this issue in Spring Boot integration tests How to reproduce: create some static inner class and try to capture its logs - it will write logs as expected but nothing will be captured It happens because Class.getName() on static inner class will return something like org.example.untitled.Main$Inner but for correct capturing we need org.example.untitled.Main.Inner which can be returned by Class.getCanonicalName() (also may return null in some cases so I used Optional)

    Also fixed some javadoc warnings from build log

    Please review and give me some feedback) Thx

    opened by AkaZver 8
  • Added tear down for log captor, small enhancements

    Added tear down for log captor, small enhancements

    Hello!

    I discovered that if you attach captor for class it will never be detached and could potentially affect other tests, because all appenders are still visible between tests. So I decided to add a method to safely detach captor by direct call (maybe in @AfterAll) or via try-with-resources.

    Btw, all attached appenders had no name and you couldn't identify which one was attached by library. Also I forgot to rename variable with MDC)

    Thank you.

    opened by AkaZver 8
  • Prevent all loggers from printing to stdout

    Prevent all loggers from printing to stdout

    Is your feature request related to a problem? Please describe. When LogCaptor is launched, it makes all loggers log to the most verbose level, and they print to stdout. This is making my tests slow by an order of magnitude (from less than 1s to around 5s), because some libraries I invoke in the tests log very heavily.

    More so, in some tests where the input data is very large and it happens to gets logged by an underlying library, the tests time out because the printing to stdout takes very long. I could work around this using .disableLogs, but that couples my test to a bunch of internal class names of the underlying library.

    Describe the solution you'd like I would like to have a way to configure LogCaptor to prevent all loggers from printing to stdout. This would not change how logging levels are currently handled by LogCaptor (as opposed to what .disableLogs does). The logged messages and objects would still be kept in memory in order to later assert against them with the current API.

    This could even be the default behavior, although that might be a breaking change for some people.

    In case it is not the default behaviour, it could be configured with an environment variable. What do you think?

    Describe alternatives you've considered An alternative is to manually disable all printing to stdout altogether. However, this would wipe out all other strings printed to stdout which are not logs (e.g. messages from the test runner or other testing libraries).

    Another alternative is to add one .disableLogs call per verbose logging class somewhere before the test starts running, but that's fragile as it couples the tests to the logging implementation of each verbose logging library.

    enhancement no-activity 
    opened by angelsanzn 8
  • Running the unit test directly from IDEA gives error

    Running the unit test directly from IDEA gives error

    Describe the bug when running test class via intellij idea : IntelliJ IDEA 2021.3.1 I get the following:

    /usr/lib/jvm/java-1.11.0-openjdk-amd64/bin/java -ea -Didea.test.cyclic.buffer.size=1048576 -javaagent:/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/213.6461.79/lib/idea_rt.jar=43869:/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/213.6461.79/bin -Dfile.encoding=UTF-8 -classpath /.m2/repository/org/junit/platform/junit-platform-launcher/1.7.2/junit-platform-launcher-1.7.2.jar:/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/213.6461.79/lib/idea_rt.jar:/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/213.6461.79/plugins/junit/lib/junit5-rt.jar:/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/213.6461.79/plugins/junit/lib/junit-rt.jar:/.m2/repository/org/threeten/threetenbp/1.5.1/threetenbp-1.5.1.jar:/.m2/repository/com/google/guava/guava/31.0.1-jre/guava-31.0.1-jre.jar:/.m2/repository/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar:/.m2/repository/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:/.m2/repository/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar:/.m2/repository/org/checkerframework/checker-qual/3.12.0/checker-qual-3.12.0.jar:/.m2/repository/com/google/errorprone/error_prone_annotations/2.7.1/error_prone_annotations-2.7.1.jar:/.m2/repository/com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.jar:/.m2/repository/org/slf4j/slf4j-log4j12/1.7.32/slf4j-log4j12-1.7.32.jar:/.m2/repository/org/slf4j/slf4j-api/1.7.32/slf4j-api-1.7.32.jar:/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar:/.m2/repository/org/springframework/boot/spring-boot-starter-security/2.5.4/spring-boot-starter-security-2.5.4.jar:/.m2/repository/org/springframework/boot/spring-boot-starter/2.5.4/spring-boot-starter-2.5.4.jar:/.m2/repository/org/springframework/boot/spring-boot/2.5.4/spring-boot-2.5.4.jar:/.m2/repository/org/springframework/spring-core/5.3.9/spring-core-5.3.9.jar:/.m2/repository/org/springframework/spring-jcl/5.3.9/spring-jcl-5.3.9.jar:/.m2/repository/org/springframework/spring-context/5.3.9/spring-context-5.3.9.jar:/.m2/repository/org/springframework/spring-aop/5.3.9/spring-aop-5.3.9.jar:/.m2/repository/org/springframework/spring-beans/5.3.9/spring-beans-5.3.9.jar:/.m2/repository/org/springframework/spring-expression/5.3.9/spring-expression-5.3.9.jar:/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.5.4/spring-boot-autoconfigure-2.5.4.jar:/.m2/repository/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar:/.m2/repository/org/yaml/snakeyaml/1.28/snakeyaml-1.28.jar:/.m2/repository/org/springframework/security/spring-security-config/5.5.2/spring-security-config-5.5.2.jar:/.m2/repository/org/springframework/security/spring-security-core/5.5.2/spring-security-core-5.5.2.jar:/.m2/repository/org/springframework/security/spring-security-crypto/5.5.2/spring-security-crypto-5.5.2.jar:/.m2/repository/org/springframework/security/spring-security-web/5.5.2/spring-security-web-5.5.2.jar:/.m2/repository/org/springframework/spring-web/5.3.9/spring-web-5.3.9.jar:/.m2/repository/ch/aaap/harvest-client/1.1.1/harvest-client-1.1.1.jar:/.m2/repository/com/squareup/retrofit2/retrofit/2.3.0/retrofit-2.3.0.jar:/.m2/repository/com/squareup/okhttp3/okhttp/3.14.9/okhttp-3.14.9.jar:/.m2/repository/com/squareup/okio/okio/1.6.0/okio-1.6.0.jar:/.m2/repository/com/squareup/retrofit2/converter-gson/2.3.0/converter-gson-2.3.0.jar:/.m2/repository/com/google/code/gson/gson/2.8.7/gson-2.8.7.jar:/.m2/repository/com/squareup/okhttp3/logging-interceptor/3.14.9/logging-interceptor-3.14.9.jar:/.m2/repository/com/fatboyindustrial/gson-javatime-serialisers/gson-javatime-serialisers/1.1.1/gson-javatime-serialisers-1.1.1.jar:/.m2/repository/org/immutables/gson/2.5.6/gson-2.5.6.jar:/.m2/repository/com/typesafe/config/1.3.3/config-1.3.3.jar:/.m2/repository/io/gsonfire/gson-fire/1.8.5/gson-fire-1.8.5.jar:/.m2/repository/org/mapstruct/mapstruct/1.4.2.Final/mapstruct-1.4.2.Final.jar:/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.12.4/jackson-datatype-jsr310-2.12.4.jar:/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.12.4/jackson-annotations-2.12.4.jar:/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.12.4/jackson-core-2.12.4.jar:/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.12.4/jackson-databind-2.12.4.jar:/.m2/repository/org/springframework/boot/spring-boot-starter-websocket/2.5.4/spring-boot-starter-websocket-2.5.4.jar:/.m2/repository/org/springframework/boot/spring-boot-starter-web/2.5.4/spring-boot-starter-web-2.5.4.jar:/.m2/repository/org/springframework/boot/spring-boot-starter-json/2.5.4/spring-boot-starter-json-2.5.4.jar:/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.12.4/jackson-datatype-jdk8-2.12.4.jar:/.m2/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.12.4/jackson-module-parameter-names-2.12.4.jar:/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/2.5.4/spring-boot-starter-tomcat-2.5.4.jar:/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.52/tomcat-embed-core-9.0.52.jar:/.m2/repository/org/apache/tomcat/embed/tomcat-embed-el/9.0.52/tomcat-embed-el-9.0.52.jar:/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.52/tomcat-embed-websocket-9.0.52.jar:/.m2/repository/org/springframework/spring-webmvc/5.3.9/spring-webmvc-5.3.9.jar:/.m2/repository/org/springframework/spring-messaging/5.3.9/spring-messaging-5.3.9.jar:/.m2/repository/org/springframework/spring-websocket/5.3.9/spring-websocket-5.3.9.jar:/.m2/repository/commons-validator/commons-validator/1.7/commons-validator-1.7.jar:/.m2/repository/commons-beanutils/commons-beanutils/1.9.4/commons-beanutils-1.9.4.jar:/.m2/repository/commons-logging/commons-logging/1.2/commons-logging-1.2.jar:/.m2/repository/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2.jar:/.m2/repository/commons-digester/commons-digester/2.1/commons-digester-2.1.jar:/.m2/repository/org/apache/poi/poi/3.14/poi-3.14.jar:/.m2/repository/commons-codec/commons-codec/1.15/commons-codec-1.15.jar:/.m2/repository/org/passay/passay/1.6.1/passay-1.6.1.jar:/.m2/repository/commons-io/commons-io/2.11.0/commons-io-2.11.0.jar:/.m2/repository/javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final.jar:/.m2/repository/org/springframework/boot/spring-boot-starter-aop/2.5.4/spring-boot-starter-aop-2.5.4.jar:/.m2/repository/org/aspectj/aspectjweaver/1.9.7/aspectjweaver-1.9.7.jar:/.m2/repository/org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar:/.m2/repository/org/apache/oltu/oauth2/org.apache.oltu.oauth2.client/1.0.1/org.apache.oltu.oauth2.client-1.0.1.jar:/.m2/repository/org/apache/oltu/oauth2/org.apache.oltu.oauth2.common/1.0.1/org.apache.oltu.oauth2.common-1.0.1.jar:/.m2/repository/org/json/json/20140107/json-20140107.jar:/.m2/repository/org/mockito/mockito-junit-jupiter/3.9.0/mockito-junit-jupiter-3.9.0.jar:/.m2/repository/org/mockito/mockito-core/4.0.0/mockito-core-4.0.0.jar:/.m2/repository/net/bytebuddy/byte-buddy/1.10.22/byte-buddy-1.10.22.jar:/.m2/repository/net/bytebuddy/byte-buddy-agent/1.10.22/byte-buddy-agent-1.10.22.jar:/.m2/repository/org/objenesis/objenesis/3.2/objenesis-3.2.jar:/.m2/repository/org/junit/jupiter/junit-jupiter-api/5.7.2/junit-jupiter-api-5.7.2.jar:/.m2/repository/org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0.jar:/.m2/repository/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.jar:/.m2/repository/org/junit/platform/junit-platform-commons/1.7.2/junit-platform-commons-1.7.2.jar:/.m2/repository/io/jsonwebtoken/jjwt-api/0.11.2/jjwt-api-0.11.2.jar:/.m2/repository/org/springframework/boot/spring-boot-starter-data-jpa/2.5.4/spring-boot-starter-data-jpa-2.5.4.jar:/.m2/repository/org/springframework/boot/spring-boot-starter-jdbc/2.5.4/spring-boot-starter-jdbc-2.5.4.jar:/.m2/repository/com/zaxxer/HikariCP/4.0.3/HikariCP-4.0.3.jar:/.m2/repository/org/springframework/spring-jdbc/5.3.9/spring-jdbc-5.3.9.jar:/.m2/repository/org/springframework/spring-tx/5.3.9/spring-tx-5.3.9.jar:/.m2/repository/jakarta/transaction/jakarta.transaction-api/1.3.3/jakarta.transaction-api-1.3.3.jar:/.m2/repository/jakarta/persistence/jakarta.persistence-api/2.2.3/jakarta.persistence-api-2.2.3.jar:/.m2/repository/org/hibernate/hibernate-core/5.4.32.Final/hibernate-core-5.4.32.Final.jar:/.m2/repository/org/jboss/logging/jboss-logging/3.4.2.Final/jboss-logging-3.4.2.Final.jar:/.m2/repository/org/javassist/javassist/3.27.0-GA/javassist-3.27.0-GA.jar:/.m2/repository/antlr/antlr/2.7.7/antlr-2.7.7.jar:/.m2/repository/org/jboss/jandex/2.2.3.Final/jandex-2.2.3.Final.jar:/.m2/repository/com/fasterxml/classmate/1.5.1/classmate-1.5.1.jar:/.m2/repository/org/dom4j/dom4j/2.1.3/dom4j-2.1.3.jar:/.m2/repository/org/hibernate/common/hibernate-commons-annotations/5.1.2.Final/hibernate-commons-annotations-5.1.2.Final.jar:/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.5/jaxb-runtime-2.3.5.jar:/.m2/repository/jakarta/xml/bind/jakarta.xml.bind-api/2.3.3/jakarta.xml.bind-api-2.3.3.jar:/.m2/repository/org/glassfish/jaxb/txw2/2.3.5/txw2-2.3.5.jar:/.m2/repository/com/sun/istack/istack-commons-runtime/3.0.12/istack-commons-runtime-3.0.12.jar:/.m2/repository/com/sun/activation/jakarta.activation/1.2.2/jakarta.activation-1.2.2.jar:/.m2/repository/org/springframework/data/spring-data-jpa/2.5.4/spring-data-jpa-2.5.4.jar:/.m2/repository/org/springframework/data/spring-data-commons/2.5.4/spring-data-commons-2.5.4.jar:/.m2/repository/org/springframework/spring-orm/5.3.9/spring-orm-5.3.9.jar:/.m2/repository/org/springframework/spring-aspects/5.3.9/spring-aspects-5.3.9.jar:/.m2/repository/org/springframework/security/spring-security-jwt/1.1.1.RELEASE/spring-security-jwt-1.1.1.RELEASE.jar:/.m2/repository/org/bouncycastle/bcpkix-jdk15on/1.64/bcpkix-jdk15on-1.64.jar:/.m2/repository/org/bouncycastle/bcprov-jdk15on/1.64/bcprov-jdk15on-1.64.jar:/.m2/repository/com/h2database/h2/1.4.200/h2-1.4.200.jar:/.m2/repository/org/apache/xmlbeans/xmlbeans/2.6.0/xmlbeans-2.6.0.jar:/.m2/repository/stax/stax-api/1.0.1/stax-api-1.0.1.jar:/.m2/repository/io/jsonwebtoken/jjwt-impl/0.11.2/jjwt-impl-0.11.2.jar:/.m2/repository/org/apache/poi/poi-ooxml/3.14/poi-ooxml-3.14.jar:/.m2/repository/org/apache/poi/poi-ooxml-schemas/3.14/poi-ooxml-schemas-3.14.jar:/.m2/repository/com/github/virtuald/curvesapi/1.03/curvesapi-1.03.jar:/.m2/repository/com/squareup/okhttp/logging-interceptor/2.7.5/logging-interceptor-2.7.5.jar:/.m2/repository/com/squareup/okhttp/okhttp/2.7.5/okhttp-2.7.5.jar:/.m2/repository/org/springframework/boot/spring-boot-starter-test/2.5.4/spring-boot-starter-test-2.5.4.jar:/.m2/repository/org/springframework/boot/spring-boot-test/2.5.4/spring-boot-test-2.5.4.jar:/.m2/repository/org/springframework/boot/spring-boot-test-autoconfigure/2.5.4/spring-boot-test-autoconfigure-2.5.4.jar:/.m2/repository/com/jayway/jsonpath/json-path/2.5.0/json-path-2.5.0.jar:/.m2/repository/net/minidev/json-smart/2.4.7/json-smart-2.4.7.jar:/.m2/repository/net/minidev/accessors-smart/2.4.7/accessors-smart-2.4.7.jar:/.m2/repository/org/ow2/asm/asm/9.1/asm-9.1.jar:/.m2/repository/org/assertj/assertj-core/3.19.0/assertj-core-3.19.0.jar:/.m2/repository/org/hamcrest/hamcrest/2.2/hamcrest-2.2.jar:/.m2/repository/org/junit/jupiter/junit-jupiter/5.7.2/junit-jupiter-5.7.2.jar:/.m2/repository/org/junit/jupiter/junit-jupiter-params/5.7.2/junit-jupiter-params-5.7.2.jar:/.m2/repository/org/junit/jupiter/junit-jupiter-engine/5.7.2/junit-jupiter-engine-5.7.2.jar:/.m2/repository/org/junit/platform/junit-platform-engine/1.7.2/junit-platform-engine-1.7.2.jar:/.m2/repository/org/skyscreamer/jsonassert/1.5.0/jsonassert-1.5.0.jar:/.m2/repository/com/vaadin/external/google/android-json/0.0.20131108.vaadin1/android-json-0.0.20131108.vaadin1.jar:/.m2/repository/org/springframework/spring-test/5.3.9/spring-test-5.3.9.jar:/.m2/repository/org/xmlunit/xmlunit-core/2.8.2/xmlunit-core-2.8.2.jar:/.m2/repository/org/mapstruct/mapstruct-processor/1.4.2.Final/mapstruct-processor-1.4.2.Final.jar:/.m2/repository/org/apache/poi/poi-scratchpad/3.14/poi-scratchpad-3.14.jar:/.m2/repository/io/jsonwebtoken/jjwt-jackson/0.11.2/jjwt-jackson-0.11.2.jar:/.m2/repository/org/springframework/boot/spring-boot-properties-migrator/2.5.4/spring-boot-properties-migrator-2.5.4.jar:/.m2/repository/org/springframework/boot/spring-boot-configuration-metadata/2.5.4/spring-boot-configuration-metadata-2.5.4.jar:/.m2/repository/mysql/mysql-connector-java/8.0.26/mysql-connector-java-8.0.26.jar:/.m2/repository/org/springframework/boot/spring-boot-configuration-processor/2.5.4/spring-boot-configuration-processor-2.5.4.jar:/.m2/repository/org/apache/poi/ooxml-schemas/1.3/ooxml-schemas-1.3.jar:/.m2/repository/io/springfox/springfox-swagger2/3.0.0/springfox-swagger2-3.0.0.jar:/.m2/repository/io/springfox/springfox-spi/3.0.0/springfox-spi-3.0.0.jar:/.m2/repository/io/springfox/springfox-core/3.0.0/springfox-core-3.0.0.jar:/.m2/repository/org/springframework/plugin/spring-plugin-core/2.0.0.RELEASE/spring-plugin-core-2.0.0.RELEASE.jar:/.m2/repository/org/springframework/plugin/spring-plugin-metadata/2.0.0.RELEASE/spring-plugin-metadata-2.0.0.RELEASE.jar:/.m2/repository/io/springfox/springfox-schema/3.0.0/springfox-schema-3.0.0.jar:/.m2/repository/io/springfox/springfox-swagger-common/3.0.0/springfox-swagger-common-3.0.0.jar:/.m2/repository/io/springfox/springfox-spring-web/3.0.0/springfox-spring-web-3.0.0.jar:/.m2/repository/io/github/classgraph/classgraph/4.8.83/classgraph-4.8.83.jar:/.m2/repository/io/springfox/springfox-spring-webmvc/3.0.0/springfox-spring-webmvc-3.0.0.jar:/.m2/repository/io/swagger/swagger-annotations/1.5.20/swagger-annotations-1.5.20.jar:/.m2/repository/io/swagger/swagger-models/1.5.20/swagger-models-1.5.20.jar:/.m2/repository/io/swagger/core/v3/swagger-annotations/2.1.2/swagger-annotations-2.1.2.jar:/.m2/repository/io/springfox/springfox-spring-webflux/3.0.0/springfox-spring-webflux-3.0.0.jar:/.m2/repository/org/springframework/security/spring-security-test/5.5.2/spring-security-test-5.5.2.jar:/.m2/repository/org/springframework/boot/spring-boot-maven-plugin/2.5.6/spring-boot-maven-plugin-2.5.6.jar:/.m2/repository/org/springframework/boot/spring-boot-buildpack-platform/2.5.4/spring-boot-buildpack-platform-2.5.4.jar:/.m2/repository/net/java/dev/jna/jna-platform/5.7.0/jna-platform-5.7.0.jar:/.m2/repository/net/java/dev/jna/jna/5.7.0/jna-5.7.0.jar:/.m2/repository/org/apache/commons/commons-compress/1.20/commons-compress-1.20.jar:/.m2/repository/org/apache/httpcomponents/httpclient/4.5.13/httpclient-4.5.13.jar:/.m2/repository/org/apache/httpcomponents/httpcore/4.4.14/httpcore-4.4.14.jar:/.m2/repository/org/tomlj/tomlj/1.0.0/tomlj-1.0.0.jar:/.m2/repository/org/antlr/antlr4-runtime/4.7.2/antlr4-runtime-4.7.2.jar:/.m2/repository/org/springframework/boot/spring-boot-loader-tools/2.5.4/spring-boot-loader-tools-2.5.4.jar:/.m2/repository/org/apache/maven/shared/maven-common-artifact-filters/3.2.0/maven-common-artifact-filters-3.2.0.jar:/.m2/repository/org/apache/maven/maven-artifact/3.1.1/maven-artifact-3.1.1.jar:/.m2/repository/org/codehaus/plexus/plexus-utils/3.2.1/plexus-utils-3.2.1.jar:/.m2/repository/org/apache/maven/maven-model/3.1.1/maven-model-3.1.1.jar:/.m2/repository/org/apache/maven/maven-core/3.1.1/maven-core-3.1.1.jar:/.m2/repository/org/apache/maven/maven-settings/3.1.1/maven-settings-3.1.1.jar:/.m2/repository/org/apache/maven/maven-settings-builder/3.1.1/maven-settings-builder-3.1.1.jar:/.m2/repository/org/codehaus/plexus/plexus-interpolation/1.19/plexus-interpolation-1.19.jar:/.m2/repository/org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.jar:/.m2/repository/org/sonatype/plexus/plexus-sec-dispatcher/1.3/plexus-sec-dispatcher-1.3.jar:/.m2/repository/org/sonatype/plexus/plexus-cipher/1.4/plexus-cipher-1.4.jar:/.m2/repository/org/apache/maven/maven-repository-metadata/3.1.1/maven-repository-metadata-3.1.1.jar:/.m2/repository/org/apache/maven/maven-plugin-api/3.6.3/maven-plugin-api-3.6.3.jar:/.m2/repository/org/eclipse/sisu/org.eclipse.sisu.plexus/0.0.0.M5/org.eclipse.sisu.plexus-0.0.0.M5.jar:/.m2/repository/javax/enterprise/cdi-api/1.0/cdi-api-1.0.jar:/.m2/repository/javax/annotation/jsr250-api/1.0/jsr250-api-1.0.jar:/.m2/repository/javax/inject/javax.inject/1/javax.inject-1.jar:/.m2/repository/org/sonatype/sisu/sisu-guice/3.1.0/sisu-guice-3.1.0-no_aop.jar:/.m2/repository/aopalliance/aopalliance/1.0/aopalliance-1.0.jar:/.m2/repository/org/eclipse/sisu/org.eclipse.sisu.inject/0.0.0.M5/org.eclipse.sisu.inject-0.0.0.M5.jar:/.m2/repository/org/codehaus/plexus/plexus-classworlds/2.6.0/plexus-classworlds-2.6.0.jar:/.m2/repository/org/apache/maven/maven-model-builder/3.1.1/maven-model-builder-3.1.1.jar:/.m2/repository/org/apache/maven/maven-aether-provider/3.1.1/maven-aether-provider-3.1.1.jar:/.m2/repository/org/eclipse/aether/aether-api/0.9.0.M2/aether-api-0.9.0.M2.jar:/.m2/repository/org/eclipse/aether/aether-spi/0.9.0.M2/aether-spi-0.9.0.M2.jar:/.m2/repository/org/eclipse/aether/aether-util/0.9.0.M2/aether-util-0.9.0.M2.jar:/.m2/repository/org/eclipse/aether/aether-impl/0.9.0.M2/aether-impl-0.9.0.M2.jar:/.m2/repository/org/apache/maven/shared/maven-shared-utils/3.3.3/maven-shared-utils-3.3.3.jar:/.m2/repository/org/sonatype/plexus/plexus-build-api/0.0.7/plexus-build-api-0.0.7.jar:/.m2/repository/org/liquibase/liquibase-core/4.6.1/liquibase-core-4.6.1.jar:/.m2/repository/javax/xml/bind/jaxb-api/2.3.1/jaxb-api-2.3.1.jar:/.m2/repository/javax/activation/javax.activation-api/1.2.0/javax.activation-api-1.2.0.jar:/.m2/repository/jakarta/activation/jakarta.activation-api/1.2.2/jakarta.activation-api-1.2.2.jar:/.m2/repository/io/github/hakky54/logcaptor/2.7.8/logcaptor-2.7.8.jar:/.m2/repository/ch/qos/logback/logback-classic/1.2.5/logback-classic-1.2.5.jar:/.m2/repository/ch/qos/logback/logback-core/1.2.5/logback-core-1.2.5.jar:/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.14.1/log4j-to-slf4j-2.14.1.jar:/.m2/repository/org/apache/logging/log4j/log4j-api/2.14.1/log4j-api-2.14.1.jar:/.m2/repository/org/slf4j/jul-to-slf4j/1.7.32/jul-to-slf4j-1.7.32.jar:/.m2/repository/com/samskivert/jmustache/1.15/jmustache-1.15.jar com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit5 org.me.MyTest SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/.m2/repository/org/slf4j/slf4j-log4j12/1.7.32/slf4j-log4j12-1.7.32.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/.m2/repository/ch/qos/logback/logback-classic/1.2.5/logback-classic-1.2.5.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]

    java.lang.IllegalArgumentException: SLF4J Logger implementation should be of the type [ch.qos.logback.classic.Logger] but found [org.slf4j.impl.Log4jLoggerAdapter].

    at nl.altindag.log.util.ValidationUtils.requireLoggerOfType(ValidationUtils.java:36)
    at nl.altindag.log.LogCaptor.<init>(LogCaptor.java:55)
    at nl.altindag.log.LogCaptor.forClass(LogCaptor.java:82)
    at org.me.MyTest.<init>(MyKeysTest.java:11)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
    at org.junit.platform.commons.util.ReflectionUtils.newInstance(ReflectionUtils.java:513)
    at org.junit.jupiter.engine.execution.ConstructorInvocation.proceed(ConstructorInvocation.java:56)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.api.extension.InvocationInterceptor.interceptTestClassConstructor(InvocationInterceptor.java:72)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:77)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestClassConstructor(ClassBasedTestDescriptor.java:342)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateTestClass(ClassBasedTestDescriptor.java:289)
    at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.instantiateTestClass(ClassTestDescriptor.java:79)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:267)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:259)
    

    To Reproduce

    1. Simple spring boot 2.5.4

    Expected behavior to run without errors like in maven but with debugging

    Screenshots

    Environmental Data:

    • Java Version 11
    • Maven Version 3.+
    • OS (Linux)

    Additional context probebly more config error on idea side then code bug

    opened by unnamedsos 7
  • Logcaptor error logs do not contain expected content when reusing instance

    Logcaptor error logs do not contain expected content when reusing instance

    Describe the bug I use logcaptor in a parameterized test method of a @SpringBootIntegrationTest class to check whether the expected error message was actually logged. I loosely followed the reuse example from the readme (see code snippets below).

    For every parameterization, one error message is logged in the sut (verified that via debugger). When looking at the logcaptor.getErrorLogs though, this is not always correctly reflected there.

    I tried out some things and it appears as if the following things make a difference:

    • Just running the test method vs. running the whole test class
    • Reusing the logcaptor instance or creating a new one every time
    • Having the logcaptor field as an instance variable vs. making it static

    The possible results for the assertion whether the specific error message has been logged are:

    • Everything ok
    • Assertion fails only for the first parameterized method call
    • Assertion fails for all parameterizations

    | | static field, reuse | non-static field, reuse | static field, no reuse | non-static field, no reuse | |---|---|---|---|---| | ran test method | all fail | first fails | ok | ok | | ran test class | all fail | ok | ok | ok |

    To Reproduce

    @SpringBootIntegrationTest
    class TestClass {
    //    LogCaptor logcaptor;
    //    static LogCaptor logcaptor;
    //    LogCaptor logcaptor = LogCaptor.forClass(Sut.class);
    
        @Autowired
        Sut sut;
        
        @BeforeEach
        void beforeEach() {
    //        logcaptor = LogCaptor.forClass(Sut.class);
    //        logcaptor.clearLogs();
        }
    
        private static Stream<List<String>> provideParameters() {
            return Stream.of(
                    null,
                    List.of()
            );
        }
    
        @ParameterizedTest
        @MethodSource("provideParameters")
        void testMethod(List<String> parameters) {
            CompletableFuture<void> future = sut.doStuff(parameters);
            assertThrows(Exception.class, () -> future.get(10, TimeUnit.SECONDS));
            assertThat(logcaptor.getErrorLogs()).containsExactly("Expected error message");
        }
    }
    
    In Sut:
    
    @Async
    public CompletableFuture<Void> doStuff(List<String> params) {
        if (params == null || params.isEmpty()) {
            var errorMessage = "Expected error message";
            log.error(errorMessage);
            return CompletableFuture.failedFuture(new Exception(errorMessage));
        }
    
        try {
            // do stuff
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return CompletableFuture.failedFuture(e);
        }
    
        return CompletableFuture.completedFuture(null);
    }
    

    Expected behavior I would have expected logCaptor.getErrorLogs to contain the expected error message no matter how the test method is run and no matter how the lagCaptor is defined and (re)used.

    Environmental Data:

    • Logcaptor 2.7.0
    • junit 5.7.2
    • jul-to-slf4j 1.7.32
    • slf4j-api 1.7.32
    • log4j-to-slf4j 2.14.1
    • log4j-api 2.14.1
    • Java 16.0.2
    • Gradle 7.1.1
    • Windows 10
    opened by Emprah 7
  • ConcurrentModificationException in getLogs()

    ConcurrentModificationException in getLogs()

    We tried LogCaptor in some integration-style tests, where logging actually happens in background thread. Occasionally getLogs() throws ConcurrentModificationException - quick look into code shows that ListAppender.list is not thread-safe, so it's almost certainly a race between test and application threads. I think it's not a problem for actual logging since AppenderBase::doAppend is synchronized, but it is a problem when scanning the list. One possible fix would be to wrap all access to list into synchronized(listAppender). Or, maybe even better, swap it for CopyOnWrite / Collections::synchronizedList. Any views on that? Happy to submit PR as well.

    opened by AndreyNudko 7
  • consoleCaptor.getStandardOutput() doesn't work

    consoleCaptor.getStandardOutput() doesn't work

    Describe the bug Hello, My issue is that with the same way as it is explained in the README I tried to use consoleCaptor.getStandardOutput() since I'm using @QuarkusTest but it gets nothing from the output, Even though the console is showing multiple json logs in the output.

    @QuarkusTest
    public class TestLog {
    
      ObjectMapper mapper = new ObjectMapper();
    
      @Test
      public void testLogIsInJsonFormat() {
        try (ConsoleCaptor consoleCaptor = new ConsoleCaptor()) {
    
          QueryClass query = new QueryClass();
          query.querySomeItem(null, null);
          List<String> standardOutPut = consoleCaptor.getStandardOutput(); // this list returns empty
    
          assertTrue(isValid(standardOutPut.get(1)));
        }
      }
    }
    
    {"timestamp":"2022-08-10T09:32:41.109+03:00","sequence":76,"loggerClassName":"org.jboss.logging.Logger","loggerName":"io.quarkus.amazon.lambda.runtime.AbstractLambdaPollLoop","level":"INFO","message":"Listening on: http://localhost:8081/_lambda_/2018-06-01/runtime/invocation/next","threadName":"Lambda Thread (TEST)","threadId":127,"mdc":{},"ndc":"","hostName":"my-laptop-name","processName":"JUnitStarter","processId":48118}
    
    java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 0 // This means nothing was captured from the logs
    
        <dependency>
          <groupId>io.github.hakky54</groupId>
          <artifactId>logcaptor</artifactId>
          <version>2.7.10</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>io.github.hakky54</groupId>
          <artifactId>consolecaptor</artifactId>
          <version>1.0.2</version>
          <scope>test</scope>
        </dependency>
    

    I suspect that maybe because I'm using @JbossLog annotation, but then how this can be used with that JBossLog ?

    Environmental Data:

    • Java Version 17
    • Maven Version 3.8.5
    • OS (MacOS)
    no-activity 
    opened by Jerilok 6
  • Not working with org.jacoco:jacoco-maven-plugin

    Not working with org.jacoco:jacoco-maven-plugin

    Hi, I just updated a large project from java 11 to 17 and introduced log-captor for unit testing.

    Now all my test are fine in the IDE, but when running them in the CI/CD pipeline on the server or locally with "./mvnw org.jacoco:jacoco-maven-plugin:prepare-agent test -Dmaven.test.failure=true"

    I face failing tests depending on the environment these are different test. Always the log-captor seems to miss some logging.

    This is how the pom looks like:

     <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <version>2.22.2</version>
                        <configuration>
                            <excludes>
                                <exclude>**/*IntegrationTest.java</exclude>
                                <exclude>**/*PerformanceTest.java</exclude>
                            </excludes>
                            <classpathDependencyExcludes>
                                <classpathDependencyExclude>org.apache.logging.log4j:log4j-slf4j-impl</classpathDependencyExclude>
                            </classpathDependencyExcludes>
                        </configuration>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-failsafe-plugin</artifactId>
                        <version>2.22.2</version>
                        <configuration>
                            <classpathDependencyExcludes>
                                <classpathDependencyExclude>org.apache.logging.log4j:log4j-slf4j-impl</classpathDependencyExclude>
                            </classpathDependencyExcludes>
                        </configuration>
                    </plugin>
                    <plugin>
                        <groupId>org.jacoco</groupId>
                        <artifactId>jacoco-maven-plugin</artifactId>
                        <configuration>
                            <excludes>
                                <exclude>**/*IntegrationTest.*</exclude>
                                <exclude>**/*PerformanceTest.*</exclude>
                            </excludes>
                        </configuration>
                    </plugin>
    

    Any ideas what might go wrong?

    opened by recumbentseeker 6
Owner
Hakan Altındağ is a freelance Java and Search Engineer
null
Most popular Mocking framework for unit tests written in Java

Most popular mocking framework for Java Current version is 3.x Still on Mockito 1.x? See what's new in Mockito 2! Mockito 3 does not introduce any bre

mockito 13.6k Jan 9, 2023
PowerMock is a Java framework that allows you to unit test code normally regarded as untestable.

Writing unit tests can be hard and sometimes good design has to be sacrificed for the sole purpose of testability. Often testability corresponds to go

PowerMock 3.9k Dec 28, 2022
PowerMock is a Java framework that allows you to unit test code normally regarded as untestable.

Writing unit tests can be hard and sometimes good design has to be sacrificed for the sole purpose of testability. Often testability corresponds to go

PowerMock 3.9k Dec 28, 2022
Toolkit for testing multi-threaded and asynchronous applications

ConcurrentUnit A simple, zero-dependency toolkit for testing multi-threaded code. Supports Java 1.6+. Introduction ConcurrentUnit was created to help

Jonathan Halterman 406 Dec 30, 2022
Java DSL for easy testing of REST services

Testing and validation of REST services in Java is harder than in dynamic languages such as Ruby and Groovy. REST Assured brings the simplicity of usi

REST Assured 6.2k Dec 31, 2022
Cucumber DSL for testing RESTful Web Services

cukes-rest takes simplicity of Cucumber and provides bindings for HTTP specification. As a sugar on top, cukes-rest adds steps for storing and using r

C.T.Co 100 Oct 18, 2022
A modern testing and behavioural specification framework for Java 8

Introduction If you're a Java developer and you've seen the fluent, modern specification frameworks available in other programming languages such as s

Richard Warburton 250 Sep 12, 2022
Randomized Testing (Core JUnit Runner, ANT, Maven)

RANDOMIZED TESTING ================== JUnit test runner and plugins for running JUnit tests with pseudo-randomness. See the following for more infor

null 167 Dec 26, 2022
JVM version of Pact. Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.

pact-jvm JVM implementation of the consumer driven contract library pact. From the Ruby Pact website: Define a pact between service consumers and prov

Pact Foundation 962 Dec 31, 2022
A programmer-oriented testing framework for Java.

JUnit 4 JUnit is a simple framework to write repeatable tests. It is an instance of the xUnit architecture for unit testing frameworks. For more infor

JUnit 8.4k Jan 4, 2023
The Enterprise-ready testing and specification framework.

Spock Framework Spock is a BDD-style developer testing and specification framework for Java and Groovy applications. To learn more about Spock, visit

Spock Framework 3.3k Jan 5, 2023
TestNG testing framework

Documentation available at TestNG's main web site. Release Notes 7.4.0 7.3.0 7.1.0 7.0.0 Need help? Before opening a new issue, did you ask your quest

Cedric Beust 1.8k Jan 5, 2023
Layout and functional testing framework for websites

Galen Framework master: Galen is an open-source tool for testing layout and responsive design of web applications. It is also a powerfull functional t

Galen Framework 1.4k Dec 10, 2022
Java DSL for easy testing of REST services

Testing and validation of REST services in Java is harder than in dynamic languages such as Ruby and Groovy. REST Assured brings the simplicity of usi

REST Assured 6.2k Dec 25, 2022
🎉Back end module of Sonic UI automation testing platform. Sonic-UI自动化测试平台后端模块。

?? Sonic UI automation testing platform. English | 简体中文 Background What is sonic ? Nowadays, automation testing, remote control and other technologies

Eason 1.7k Jan 1, 2023
Advanced Java library for integration testing, mocking, faking, and code coverage

Codebase for JMockit 1.x releases - Documentation - Release notes How to build the project: use JDK 1.8 or newer use Maven 3.6.0 or newer; the followi

The JMockit Testing Toolkit 439 Dec 9, 2022
JVM version of Pact Enables consumer driven contract testing

JVM version of Pact. Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.

Pact Foundation 961 Dec 30, 2022
State of the art mutation testing system for the JVM

Pitest (aka PIT) is a state of the art mutation testing system for Java and the JVM. Read all about it at http://pitest.org Releases 1.7.3 #952 Mutate

Henry Coles 1.5k Dec 26, 2022