5

I have an application that is a mix of Spring Boot, Jersey, and Camel applications. It starts as a Spring Boot app. I am writing integration tests, and I need to make asserts on logs?

For instance, I need to assert that the Camel route read a message from source A. How can I make reliable asserts on logs? Is there any industry standard for this?

NOTE: I tried finding any solution, but at the moment, I neither understand how to solve it nor can find ready solutions.

UPDATE 1: The detail that I underestimated, but it seems important. I use Kotlin, NOT Java. I tried applying answer, but it isn't one to one transferable to Kotlin.

UPDATE 2:

This is a conversion from Java to Kotlin. ListAppender doesn't have enough information to resolve the type in Kotlin.

class LoggerExtension : BeforeEachCallback, AfterEachCallback {
    private val listAppender: ListAppender<ILoggingEvent> = ListAppender<ILoggingEvent>()
    private val logger: Logger = LoggerFactory.getLogger(ROOT_LOGGER_NAME) as Logger

    override fun afterEach(extensionContext: ExtensionContext) {
        listAppender.stop()
        listAppender.list.clear()
        logger.detachAppender(listAppender)
    }

    override fun beforeEach(extensionContext: ExtensionContext) {
        logger.addAppender(listAppender)
        listAppender.start()
    }

    val messages: List<String>
        get() = listAppender.list.stream().map { e -> e.getMessage() }.collect(Collectors.toList())
    val formattedMessages: List<String>
        get() = listAppender.list.stream().map { e -> e.getFormattedMessage() }.collect(Collectors.toList())
}

Kotlin: Not enough information to infer type variable A

Not an error, but I have a feeling that it will fail in runtime:

private val logger: Logger = LoggerFactory.getLogger(ROOT_LOGGER_NAME) as Logger

Dmytro Chasovskyi
  • 3,209
  • 4
  • 40
  • 82
  • what doesn't work for the answer you mentioned? Any error? – sidgate Feb 25 '21 at 19:21
  • I don't know if my experience is unusual, but I've never considered log output as part of the contract of a function/class/system, and so never wanted to test it.  Log output varies a lot: it depends on log levels and config, and developers often add/change/remove logging as needed to investigate issues — you don't want tests to fail every time they do.  And logs are generally for human eyes, not for machines to parse, so logging changes shouldn't break anything anyway.  If you have important output, have you considered writing it somewhere _other_ than the logs? – gidds Feb 25 '21 at 21:28
  • @gidds It is a good question. Theoretically, it is possible to redirect all logs to the file and assert in files, but how it differs from asserting logs. Also, in my case, we have a microservice architecture, and I want to know if Camel read the message from the queue. As I want to know if the route worked correctly, I don't see a better way to test than analyzing logs. I guess this practice specific to the Apache Camel framework. – Dmytro Chasovskyi Feb 25 '21 at 21:35

1 Answers1

13

Spring Boot comes with OutputCapture rule for JUnit 4 and OutputCaptureExtension for JUnit 5, that let you assert on text sent to standard output.

public class MyTest {

     @Rule
     public OutputCaptureRule output = new OutputCaptureRule();

     @Test
     public void test() {
         // test code
         assertThat(output).contains("ok");
     }

 }
Maciej Walkowiak
  • 12,372
  • 59
  • 63