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

Dhe*_*rik 7 java testing spring mocking spring-boot

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

@RunWith(SpringRunner.class)
@WebMvcTest(MyController.class)
class MyControllerTest {
Run Code Online (Sandbox Code Playgroud)

我正在测试的方法仅使用 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();
    }

}
Run Code Online (Sandbox Code Playgroud)

我认为这个解决方案对于这些注释并不优雅......声明的 s2 和 s3 似乎没有被阅读代码的人使用。注入到 MyController 中的每个服务都需要与@MockBean.

所以,我有两个问题:

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

dav*_*xxx 7

第一个问题:

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

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

Spring 文档确认:

41.3.7 自动配置的 Spring MVC 测试

通常@WebMvcTest 将被限制为单个控制器并与@MockBean 结合使用为所需的协作者提供模拟实现。

所以在你的情况下,你别无选择。

第二个问题:

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

我认为您可以通过使用@MockBeanfor 字段来模拟测试中的特定内容以及@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();
    }

}
Run Code Online (Sandbox Code Playgroud)