【问题标题】:How to autowire MockMvc bean correctly如何正确自动装配 MockMvc bean
【发布时间】:2019-07-03 19:56:01
【问题描述】:

我有点麻烦。

我正在尝试测试我的 Spring Boot 应用程序的 Web 层(使用 JUnit5)。
我正在使用@WebMvcTest(NoteController::class) 允许我自动连接MockMvc 以模拟请求。

但我收到以下错误:
kotlin.UninitializedPropertyAccessException: lateinit property mvc has not been initialized

NoteControllerTest

import org.hamcrest.Matchers.`is`
import org.junit.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.http.MediaType
import org.springframework.test.context.junit.jupiter.SpringExtension
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.*

@ExtendWith(SpringExtension::class)
@WebMvcTest(NoteController::class)
class NoteControllerTest {

    @Autowired
    private lateinit var mvc: MockMvc

    @Test
    fun should_create_a_note() {
        mvc.perform(
                post("/notes"))
                .andExpect(status().isCreated)
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(jsonPath("$.content", `is`("my content")))
    }
}

NoteController

import fr.$$.$$.api.CreateNote
import fr.$$.$$.api.FetchNote
import fr.$$.$$.resources.Note
import fr.$$.$$.resources.toResource
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RestController
import java.net.URI

@RestController("/notes")
class NoteController(val createNote: CreateNote,
                     val fetchNote: FetchNote) {

    @GetMapping
    fun getAllNotes(): ResponseEntity<List<Note>> {
        return ResponseEntity(fetchNote.all().toResource(), HttpStatus.OK)
    }

    @PostMapping
    fun createNote(): ResponseEntity<Note> {
        val note = createNote.with("my content").toResource()
        return ResponseEntity.created(URI("")).body(note)
    }
}

SmartNotesApplicationTest

import org.junit.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT
import org.springframework.test.context.junit.jupiter.SpringExtension

@ExtendWith(SpringExtension::class)
@SpringBootTest(webEnvironment = RANDOM_PORT)
class SmartNotesApplicationTest {

    @Test
    fun contextLoad() {

    }
}

提前致谢。

【问题讨论】:

  • 您正在混合使用 JUnit 4 和 JUnit 5 类型(Test 来自 JUnit 4,但 ExtendWith 来自 JUnit 5)。
  • 请注意,使用 JUnit5,除了 WebMvcTest 之外,您不需要 ExtendWith(SpringExtension::class),因为 WebMvcTest 已经使用 ExtendWith(SpringExtension::class) 进行了元注释
  • 谢谢,没注意到!

标签: spring-mvc kotlin junit5


【解决方案1】:

我注入WebApplicationContext,然后为每个测试构建一个新的MockMvc

@SpringBootTest
class SomeTest {

    @Autowired
    lateinit var webApplicationContext: WebApplicationContext
    lateinit var mockMvc: MockMvc

    @BeforeEach
    fun beforeEach() {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build()
    }

    // Tests go here!
}

【讨论】:

  • 正如@JBNizet 上面提到的,如果您正在编写 JUnit5 测试(更改您的导入),请确保使用 Junit5 @Test 注释。
  • 谢谢,我试试这个。我不能单独使用@WebMvcTest 吗?它不应该自动配置并注入MockMvc 的实例吗?
【解决方案2】:

感谢您的回答,我在 Java 中使用 Spring Boot 2.2.6 给出了有效的答案:

AuthorController.class

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(path = "/authors")

public class AuthorController {
    @GetMapping("/health")
    public boolean healthcheck() {
        return true;
    }
}

AuthorControllerIT.class

import org.junit.jupiter.api.Test;
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.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

@SpringBootTest
@AutoConfigureMockMvc
class AuthorControllerIT {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void test_web_layer() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/authors/health"))
                .andDo(MockMvcResultHandlers.print())
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.content().string("true"));
    }
}

注意: 您可以使用@WebMvcTest(AuthorController.class) 代替@SpringBootTest + AutoConfigureMockMvc

使用此注释,它只会加载网络层。 如果您的控制器中有依赖项(服务、存储库...),您必须使用:

@MockBean
private MyService service;

【讨论】:

    猜你喜欢
    • 2013-03-08
    • 1970-01-01
    • 1970-01-01
    • 2015-09-08
    • 1970-01-01
    • 2012-08-11
    • 2015-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多