代码之家  ›  专栏  ›  技术社区  ›  Martin Häusler

是否可以在没有@DirtiesContext的情况下测试Spring-REST控制器?

  •  1
  • Martin Häusler  · 技术社区  · 7 年前

    我正在开发一个Spring Boot web应用程序。编写集成测试的常用方法是:

    @Test
    @Transactional
    @Rollback(true)
    public void myTest() {
        // ...
    }
    

    只要 一个线程 完成工作。 @Rollback 如果有多个线程,则无法工作。

    但是,当测试 @RestController 使用Spring REST模板初始化,有 总是 多线程(按设计):

    • 充当客户端并运行REST模板的测试线程
    • 接收和处理请求的服务器线程

    所以你不能使用 @回滚 在休息测试中。问题是: 相反,您使用什么使测试可重复,并使它们在测试套件中很好地发挥作用?

    @DirtiesContext 工作正常,但这是一个糟糕的选择,因为在每个REST测试方法之后重新启动Spring应用程序上下文会使套件的执行速度非常慢;每个测试需要几毫秒才能运行,但重新启动上下文需要几秒钟。

    1 回复  |  直到 7 年前
        1
  •  4
  •   Arne Burmeister    7 年前

    首先,使用Spring上下文测试控制器不是单元测试。您应该考虑通过对依赖项使用mock并创建 standalone mock MVC :

    public class MyControllerTest {
      @InjectMocks
      private MyController tested;
      // add @Mock annotated members for all dependencies used by the controller here
      private MockMvc mvc;
    
      // add your tests here using mvc.perform()
      @Test
      public void getHealthReturnsStatusAsJson() throws Exception {
        mvc.perform(get("/health"))
          .andExpect(status().isOk())
          .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
          .andExpect(jsonPath("$.status", is("OK")));
      }
    
      @Before
      public void createControllerWithMocks() {
        MockitoAnnotations.initMocks(this);
        MockMvcBuilders.standaloneSetup(controller).build()
      }
    }
    

    如果使用外部 @ControllerAdvice 通过简单调用 setControllerAdvice() 在MVC生成器上。

    这样的测试在并行运行时没有问题,而且速度更快,根本不需要设置Spring上下文。

    您描述的部分集成测试对于确保使用正确的接线以及所有测试单元按预期协同工作也很有用。但我更倾向于进行更通用的集成测试,包括多个/所有端点检查它们是否正常工作(不检查边缘情况),以及仅模拟外部服务(如内部REST客户端,将数据库替换为内存中的数据库,…)。使用此设置,您可以从一个新的数据库开始,甚至可能不需要回滚任何事务。当然,使用数据库迁移框架(如 Liquibase 这将动态设置内存中的db。