UriComponentsBuilder/MvcComponentsBuilder 在 Spring 启动测试中的用法

UriComponentsBuilder/MvcComponentsBuilder usage in a Spring Boot Test

我已经放了一个非常简单的 sample project on GitHub 来重现问题。

主要问题是我有一个 PersonController 有一个 PutMapping 来创建一个新人。为了用 URL 填充 Location header 来获取那个人,我添加 UriComponentsBuilder 作为 PutMapping 的参数,如您在此处看到的:

  @PostMapping
  public ResponseEntity<Person> add(@RequestBody final PersonForCreate personForCreate, UriComponentsBuilder uriComponentsBuilder) {
    Person newPerson = new Person(this.people.size() + 1, personForCreate.getFirstName(), personForCreate.getLastName());
    this.people.add(newPerson);

    // create the URI for the "Location" header
    MvcUriComponentsBuilder.MethodArgumentBuilder methodArgumentBuilder = MvcUriComponentsBuilder.fromMappingName(uriComponentsBuilder, "getById");
    methodArgumentBuilder.arg(0, newPerson.getId());
    URI uri = URI.create(methodArgumentBuilder.build());

    return ResponseEntity.created(uri).body(newPerson);
  }

这在 运行 项目时工作正常。但是当 运行 测试时,这会导致 IllegalArgumentException No WebApplicationContext。错误来自 MvcUriComponentsBuilder.fromMappingName 调用,但我不知道为什么。

我的测试如下:

@ExtendWith(SpringExtension.class)
@WebMvcTest
class PersonControllerTest {

  @Autowired
  private PersonController personController;

  @Test
  void add() {
    this.personController.add(new PersonForCreate("Charles", "Darwin"), UriComponentsBuilder.newInstance());
  }
}

我不确定传递 UriComponentsBuilder.newInstance() 是否正确,但我尝试使用其他值并没有发现差异。

仅供参考,示例项目使用 Spring Boot 2.2.3 和 JUnit 5,但我在 JUnit 4 上使用示例项目时遇到同样的问题。

你试过 MockMvc 了吗?当您使用@WebMvcTest 时,将以处理 HTTP 请求的相同方式调用以下代码,仅调用 Web 层而不是整个上下文。

import org.junit.jupiter.api.Test;
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.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;

@WebMvcTest
class PersonControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void add() throws Exception {
        //this.personController.add(new PersonForCreate("Charles", "Darwin"), uriComponentsBuilder);
        this.mockMvc.perform(MockMvcRequestBuilders.post("/person")
                .content("{\"firstName\": \"Charles\",\"lastName\": \"Darwin\"}").contentType(MediaType.APPLICATION_JSON))
                .andDo(MockMvcResultHandlers.print())
                .andExpect(MockMvcResultMatchers.status().isCreated())
                .andExpect(MockMvcResultMatchers.content().string("{\"id\":4,\"firstName\":\"Charles\",\"lastName\":\"Darwin\"}"));
    }
}

Spring.io/guides参考

https://spring.io/guides/gs/testing-web/