繁体   English   中英

Spring Mockito - Junit控制器测试 - 模拟一项服务

[英]Spring Mockito - Junit Controller Test - Mock one service

我有一个控制器类ControllerClass ,它管理两个类服务:

  • ServiceA解析一些文件

  • ServiceB管理文件系统

我想测试ControllerClass ,特别是:

  • ServiceA Autowired类

  • ServiceB模拟这个服务,使用一个模拟类来实现intercace总是返回固定值。

我能怎么做?

@MockBean看起来很适合您的用例。

此注释的行为方式如下:

  • 如果在测试上下文中没有定义bean - 将添加新的bean
  • 如果已经定义了单个bean - 那么它将被mock替换
  • 如果已定义了两个或更多bean,则使用@Qualifier指定哪个bean应该被mock替换

在测试类中连接mock bean之后,可以将其存根,以便始终返回一些值。 例如,对于特定测试,只需在测试中添加以下内容:

    @Autowired
    private ServiceA serviceA;
    @MockBean
    private ServiceB serviceB;

    @Test
    public void testSomething() {
        when(serviceB.doSomething()).thenReturn("fixed response");
        // ...
    }

如果你想要所有测试的存根 - 将存根放在setup方法中:

    @Autowired
    private ServiceA serviceA;
    @MockBean 
    private ServiceB serviceB;

    @Before
    public void setup() {
        when(serviceB.doSomething()).thenReturn("fixed response");
    }

顺便说一句,Spring还提供了@SpyBean ,其行为与@MockBean类似。

基本上spy和mock之间没有区别,如果你对它们进行存根方法调用。 方法调用没有存根时,差异变得很明显

  • 在mock的情况下 - 没有做任何事情(如果方法返回void - 它只是没有被调用,如果方法返回一些东西 - 那么mock将返回null
  • 在间谍的情况下 - 调用真实对象的方法。

从一个简单的spring-web应用程序开始,具有以下测试:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class MyControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    public void testGreeting() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("A response: I am real ServiceA!, B response: I am real ServiceB!")));
    }
}

解决方案一

使用@MockBean和@Before:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class MyControllerMockBeanTest {

    @MockBean
    private ServiceB mockB;

    @Before
    public void setup() {
       Mockito.when(mockB.greeting()).thenReturn("I am mock Service B!");
    }
    @Autowired
    private MockMvc mvc;

    @Test
    public void testGreetingMock() throws Exception {
       mvc.perform(MockMvcRequestBuilders.get("/")
            .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(content().string(equalTo("A response: I am real ServiceA!, B response: I am mock Service B!")));
    }
}

解决方案II

使用spring配置文件和自定义测试配置:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
// activate "test" profile
@ActiveProfiles("test")
// set custom config classes (don't forget Application)
@ContextConfiguration(classes = {TestConfig.class, Application.class})
public class MyControllerTest {
    // define configuration for "test" profile (inline possible)
    @Profile("test")
    @Configuration
    static class TestConfig {

        @Bean
        // !
        @Primary
        // I had an (auto configuration) exception/clash, 
        // when using *same bean name*, so *not* 'serviceB()', plz.
        public ServiceB mockB() {
            // prepare...
            ServiceB mockService = Mockito.mock(ServiceB.class);
            Mockito.when(mockService.greeting()).thenReturn("I am Mock Service B!");
            // and return your mock object!
            return mockService;
        }
    }
    @Autowired
    private MockMvc mvc;

    @Test
    public void testGreetingMock() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("A response: I am real ServiceA!, B response: I am Mock Service B!")));
    }
}

在github上完成样本。


而且我很确定,解决方案列表并不完整

...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM