question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Logcaptor error logs do not contain expected content when reusing instance

See original GitHub issue

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

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
Emprahcommented, Dec 16, 2021

Sorry for the late answer, i was quite busy - but just wanted to return the thank you for the follow up 😃

0reactions
Hakky54commented, Jun 11, 2022

Hi @hoangbnc

Thank you for the suggestion, however this won’t solve the root issue which is causing this different behavior. Adding a reset function and calling that in the before each is not different than just initializing it at that level. I think the ideal solution for this kind of use case or rather generic use case when using spring with junit 4 or 5 would be creating a junit-extension for logcaptor which would take away all of the verbosity for creating, resetting and disposal of logcaptor in the different test phases such as before all, before each, after each and after all.

Read more comments on GitHub >

github_iconTop Results From Across the Web

LogCaptor fails to capture when using SpringBootTest and ...
The problem in the failing test is that the class variable logcaptor is created before the test application context is created.
Read more >
Release 22.2.0 Twisted Matrix Labs
An example IRC log bot - logs a channel's events to a file. ... If it reports an error (“No module named calculus”),...
Read more >
behave Documentation - Read the Docs
To find the steps directory behave will look in the directory containing the feature file. If it is not present, behave will look...
Read more >
Implementing and Administering Avaya Aura® Media Server
Documentation does not include marketing materials. Avaya shall not be ... an Instance of the Software on one Server or on multiple Servers....
Read more >
patch - Pagure.io
Because once self has opened + # it can NOT change opts on reused (ie restart) + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, reqcert) + log.debug("Using ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found