代码之家  ›  专栏  ›  技术社区  ›  michele

SpringMockito-Junit控制器测试-MockOne服务

  •  1
  • michele  · 技术社区  · 7 年前

    我有一个控制器类 控制器类

    • 服务A 解析一些文件

    • 服务B 管理文件系统的

    我想测试一下

    • 服务A 自动连线类

    • 服务B 使用一个Mock类模拟此服务,该类实现始终返回固定值的interace。

    我该怎么办?

    2 回复  |  直到 7 年前
        1
  •  8
  •   Community Mohan Dere    6 年前

    从一个简单的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&@之前:

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

    @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
  •  7
  •   Oleksii Zghurskyi    7 年前

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

    此注释的行为方式如下所示:

    • 若测试上下文中并没有定义bean,那个么将添加一个新的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");
        }
    
    

    顺便说一句,春天也提供了 @SpyBean 行为与 @MockBean .

    方法调用没有存根

    • 在mock的情况下-什么都不做(如果方法返回void-它只是不被调用,如果方法返回一些东西-那么mock将返回) 无效的
    • 在间谍的情况下,调用真实对象的方法。