The project used to be in Spring Boot 2.6.1, Java 11; now migrating to Spring Boot 3.5.4, Java 17. Here's a minimal test that doesn't work in our environment:
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit.jupiter.SpringExtension
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import org.springframework.test.web.servlet.setup.MockMvcBuilders
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.context.WebApplicationContext
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ExtendWith(SpringExtension::class)
class MyTest(
@Autowired
private val ctx: WebApplicationContext
) {
@RestController
class MyController {
@GetMapping("/foo")
fun foo() = "bar"
}
private lateinit var mockMvc: MockMvc
@BeforeEach
fun setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build()
}
@Test
fun dbg() {
println("Context ${ctx::class.qualifiedName}")
println("mockmvc: ${ctx.getBeansOfType(MockMvc::class.java)}")
}
@Test
fun foo() {
mockMvc.perform(get("/foo")).andExpect(status().isOk).andExpect(content().string("bar"))
}
}
this gives org.junit.jupiter.api.extension.ParameterResolutionException: Failed to resolve parameter [org.springframework.web.context.WebApplicationContext ctx] in constructor [public com.example.MyTest(org.springframework.web.context.WebApplicationContext)]: No qualifying bean of type 'org.springframework.web.context.WebApplicationContext' available: expected at least 1 bean which qualifies as autowire candidate
With this code (this is closer to what we had working originally):
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit.jupiter.SpringExtension
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@ExtendWith(SpringExtension::class)
class MyTest {
@RestController
class MyController {
@GetMapping("/foo")
fun foo() = "bar"
}
@Autowired
private lateinit var mockMvc: MockMvc
@Test
fun foo() {
mockMvc.perform(get("/foo")).andExpect(status().isOk).andExpect(content().string("bar"))
}
}
the error is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.example.MyTest': Unsatisfied dependency expressed through field 'mockMvc': No qualifying bean of type 'org.springframework.test.web.servlet.MockMvc' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} (and that was exactly the error I was getting for ogirinal tests).
Please suggest what can I be missing. Dependency implementation("org.springframework.boot:spring-boot-starter-web") is present.
Figured it out eventually. The company uses a complicated system of profiles, and the profile used for tests contains a (well-hidden) spring.main.web-application-type: none. Which earlier did not prevent MockMVC from autowiring somehow. But now this property is parsed correctly, and the application is not considered a web application, so no WebApplicationContext, so no MockMVCs. The solution is to set type to servlet.