Assertion calls on CapturedOutput with Kotlin are very slow
See original GitHub issueI have a test that checks to see if a string is in the captured output. I expect this to work because CapturedOutput implements CharSequence. However, the test hangs indefinitely.
// this test hangs indefinitely
@Test
fun `check if output contains string`(output: CapturedOutput) {
assertAll(
{ assertTrue("Started" in output) },
)
}
I would expect that this works the same as if I had called output.all.
// this test works as expected
@Test
fun `check if output contains string`(output: CapturedOutput) {
assertAll(
{ assertTrue("Started" in output.all) },
)
}
- Spring Boot 2.7.2
- Kotlin 1.7.10
- Gradle 7.5.1
ApplicationTest.kt
import org.junit.jupiter.api.Assertions.assertAll
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.junit.jupiter.api.parallel.Isolated
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT
import org.springframework.boot.test.system.CapturedOutput
import org.springframework.boot.test.system.OutputCaptureExtension
import org.springframework.context.ApplicationContext
import org.springframework.test.annotation.DirtiesContext
@SpringBootTest(
classes = [Application::class],
webEnvironment = RANDOM_PORT,
)
@ExtendWith(OutputCaptureExtension::class)
internal class ApplicationTest {
@Test
fun `expect Spring Context loads`(context: ApplicationContext?) {
assertNotNull(context)
}
@Test
fun `check if output contains string`(output: CapturedOutput) {
assertAll(
{ assertTrue("Started" in output) },
)
}
}
Application.kt
import org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.TypeExcludeFilter
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.runApplication
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.ComponentScan.Filter
import org.springframework.context.annotation.FilterType.CUSTOM
import org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator
@SpringBootApplication
@ComponentScan(
excludeFilters = [
Filter(type = CUSTOM, classes = [TypeExcludeFilter::class]),
Filter(type = CUSTOM, classes = [AutoConfigurationExcludeFilter::class])
],
nameGenerator = FullyQualifiedAnnotationBeanNameGenerator::class
)
@EnableConfigurationProperties
class Application
fun main() {
try {
runApplication<Application>()
} catch (e: Exception) {
e.printStackTrace()
throw e
}
}
Issue Analytics
- State:
- Created a year ago
- Comments:6 (4 by maintainers)
Top Results From Across the Web
How to do a JUnit assert on a message in a logger
The call to setUseParentHandlers() is to silence the normal handlers, so that (for this junit-test run) no unnecessary logging happens.
Read more >JUnit 5 User Guide
1. Kotlin Assertion Support. JUnit Jupiter also comes with a few assertion methods that lend themselves well to being used in Kotlin. All...
Read more >[GitHub] [myfaces-tobago] dependabot[bot] opened a new pull ...
... <li>Assertion calls on CapturedOutput with Kotlin are very slow <a ... archiveFile property is annotated as an <code>@Input</code> but should be ...
Read more >Testing Exceptions in Kotlin with assertFailsWith - Baeldung
A quick and practical guide to Kotlin's assertFailsWith. ... in JUnit 5 that we can use to assert exceptions in Kotlin is assertThrows()....
Read more >Spring Boot Reference Documentation
The preceding instructions install a local instance of spring called the dev ... The first run of your application is slow, as dependencies...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found

I can’t reproduce the hanging test with the provided sample, but the
this test hangstest does take as long as 30 seconds to run. It is likely to take exponentially longer with more captured output (which is why you see a difference between log levelsINFOandDEBUG).The problem is specific to Kotlin. A statement like
assertTrue("Started ApplicationTest" in output)treatsoutputas aCharSequenceand invokes Kotlin’sCharSequence.contains. This calls thelength()andcharAt()methods of Spring Boot’sCapturedOutputclass many times. These methods are not very efficient, as they calltoString()and assemble a String from the captured output with each call.When calling
assertTrue("Started ApplicationTest" in output.all), the result ofoutput.allis a String so theCharSequence.containsmethod is not called and the test executes very quickly. This is essentially the same as callingassertTrue("Started ApplicationTest" in output.toString()).assertThat(output).contains("Started ApplicationTest")is also very fast.Marking this for team attention so we can decide what, if anything, we want to do about this.
I think we should add some caching to
org.springframework.boot.test.system.OutputCaptureso that repeated calls are faster.