有没有办法在Spring MVC测试中不使用@MockBean?

时间:2018-01-29 14:52:30

标签: java spring spring-boot testing mocking

我正在尝试使用@WebMvcTest测试我的Rest Controller的Rest合约,例如:

@RunWith(SpringRunner.class)
@WebMvcTest(MyController.class)
class MyControllerTest {

我正在测试的方法只使用MyFirstService,但在类中还有另外两个服务使用的另外两个服务(MySecondService和MyThirdService)。

问题在于使用@MockBean。在决赛中,测试类似乎是这样的:

@RunWith(SpringRunner.class)
@WebMvcTest(MyController.class)
class MyControllerTest { 

    @MockBean
    private MyFirstService s1; // internal method mocked for the test

    @MockBean
    private MySecondService s2; //never used

    @MockBean
    private MyThirdService s3; //never used

    ...

    @Test
    public void testMethod() [
        // mock s1
        // calls rest controller method
        MvcResult mvcResult = mvc.perform(post("/products")
            .header("Content-Type", "application/json")
            .content(json))
            .andExpect(status().isCreated())
            .andReturn();
    }

}

我认为这个解决方案并不优雅......声明的s2和s3似乎不会从读取代码的人那里使用。并且MyController中注入的每个服务都需要@MockBean

所以,我有两个问题:

  1. 有没有办法在Spring MVC测试中不使用@MockBean
  2. 有没有更好的方法来做同样的事情,即使使用@MockBean

1 个答案:

答案 0 :(得分:2)

第一个问题:

  

有没有办法在Spring MVC测试中不使用@MockBean?

@WebMvcTest允许在Spring上下文中仅配置MVC bean 作为优势,它可以隔离测试并使其执行速度更快 作为缺点,它需要为测试控制器的依赖性提供模拟,即使在测试方法中不需要它们。

Spring文档确认:

41.3.7 Auto-configured Spring MVC tests

  

@WebMvcTest通常仅限于一个控制器并在其中使用   与@MockBean组合以提供模拟实现   需要合作者。

所以在你的情况下,你没有选择权。

第二个问题:

  

有没有更好的方法来做同样的事情,即使使用@MockBean?

我认为您可以使用@MockBean为您希望在测试中模拟特定内容的字段生成更好的代码,并根据所测试的控制器将@MockBeans用于其他bean类。

没有经过测试,但您可以尝试:

@RunWith(SpringRunner.class)
@WebMvcTest(MyController.class)
@MockBeans({ @MockBean(MySecondService.class), 
             @MockBean(MyThirdService.class) 
           }) // technical mocks for the dependencies resolution

class MyControllerTest { 

    @MockBean
    private MyFirstService s1; 

    @Test
    public void testMethod() [
        // mock s1
        // calls rest controller method
        MvcResult mvcResult = mvc.perform(post("/products")
            .header("Content-Type", "application/json")
            .content(json))
            .andExpect(status().isCreated())
            .andReturn();
    }

}