设置选择

MockMvc 可以通过两种方式之一进行设置。一种是直接指向你要测试的控制器,并以编程方式配置 Web MVC 基础设施。第二种是指向包含 Web MVC 和控制器基础设施的 Infra 配置。

要设置 MockMvc 以测试特定控制器,请使用以下代码:

class MyWebTests {

  MockMvc mockMvc;

  @BeforeEach
  void setup() {
    this.mockMvc = MockMvcBuilders.standaloneSetup(new AccountController()).build();
  }

  // ...

}

或者,你也可以在通过 WebTestClient 进行测试时使用此设置,它委托给如上所示的同一个构建器。

要通过 Infra 配置设置 MockMvc,请使用以下代码:

@JUnitWebConfig(locations = "my-servlet-context.xml")
class MyWebTests {

  MockMvc mockMvc;

  @BeforeEach
  void setup(WebApplicationContext wac) {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
  }

  // ...

}

或者,你也可以在通过 WebTestClient 进行测试时使用此设置,它委托给如上所示的同一个构建器。

你应该使用哪种设置选项?

webAppContextSetup 加载你实际的 Web MVC 配置,从而产生更完整的集成测试。由于 TestContext 框架缓存加载的 Infra 配置,即使你在测试套件中引入更多测试,它也有助于保持测试运行速度。此外,你可以通过 Infra 配置将 mock 服务注入控制器,以保持专注于测试 Web 层。以下示例使用 Mockito 声明了一个 mock 服务:

<bean id="accountService" class="org.mockito.Mockito" factory-method="mock">
  <constructor-arg value="org.example.AccountService"/>
</bean>

然后,你可以将 mock 服务注入到测试中以设置并验证你的期望,如下例所示:

@JUnitWebConfig(locations = "test-servlet-context.xml")
class AccountTests {

  @Autowired
  AccountService accountService;

  MockMvc mockMvc;

  @BeforeEach
  void setup(WebApplicationContext wac) {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
  }

  // ...

}

另一方面,standaloneSetup 更接近于单元测试。它一次测试一个控制器。你可以手动注入带有 mock 依赖的控制器,它不涉及加载 Infra 配置。此类测试更侧重于风格,更容易看出正在测试哪个控制器,是否需要任何特定的 Infra MVC 配置才能工作等等。standaloneSetup 也是编写临时测试以验证特定行为或调试问题的非常便捷的方式。

正如大多数“集成与单元测试”的争论一样,没有正确或错误的答案。但是,使用 standaloneSetup 确实意味着需要额外的 webAppContextSetup 测试来验证你的 Web MVC 配置。 或者,你可以使用 webAppContextSetup 编写所有测试,以便始终针对实际的 Web MVC 配置进行测试。