春天的Mockito - Junit的控制器测试 - 模拟一个服务

问题描述 投票:1回答:2

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

  • 该解析某些文件服务
  • ServiceB用于管理文件系统

我想测试ControllerClass,特别是:

  • 服务类自动装配Autowired
  • 服务模拟这种服务,与实现总是返回固定值的接口模拟类。

我能怎么做?

java spring spring-boot
2个回答
1
投票

从下面的测试简单的弹簧的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!")));
    }
}

和解决方案

Using @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!")));
    }
}

好Souchion

Using spring profiles & custom test config:

@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!")));
    }
}

Complete sample at github.


而且我敢肯定,即解决方案的列表是不完整的。

...


2
投票

@MockBean看起来很好的候选人为您的使用情况。

这说明在行为方式如下:

  • 如果没有bean是在测试上下文中定义 - 新的将被添加
  • 如果一个bean已被定义 - 那么它将会被模拟取代
  • 如果两个或多个豆已经被定义 - 然后使用@Qualifier指定哪些人应该被嘲笑被替换

当您在您的测试类的有线模拟豆,你可以存根它,总是返回一定的价值。例如,对于具体的测试只需添加这样的事情您的测试:

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

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

如果您想存根所有测试 - 放安装方法存根:

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

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

顺便说一句,Spring还提供qazxsw类似行为qazxsw芋泥芋泥。

基本上有间谍和模拟之间没有什么区别,如果你存根方法调用它们。所不同的成为apperent,当方法调用没有存根:

  • 在模拟的情况下 - 不采取任何措施(如果方法返回void - 它只是不被调用,如果方法返回的东西 - 然后嘲笑将返回null)
  • 在间谍的情况下, - 真实物体的方法被调用。
© www.soinside.com 2019 - 2024. All rights reserved.