通过模拟服务进行弹簧控制器测试

Posted

技术标签:

【中文标题】通过模拟服务进行弹簧控制器测试【英文标题】:spring controller test by mock service 【发布时间】:2019-05-23 09:56:33 【问题描述】:

使用 Mocking 和单元测试助手更喜欢 Spring 测试:

模拟服务替换多个依赖项

enter image description here

@Controller
@RequestMapping("/people")
public class PeopleController 
    @Autowired
    protected PersonService personService;
    @GetMapping
    public ModelAndView people(Model model) 
        for (Person person: personService.getAllPeople()) 
            model.addAttribute(person.getName(), person.getAge());
        
        return new ModelAndView("people.jsp", model.asMap());
    

私有 MockMvc mockMvc:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class PeopleControllerTest 
    @Autowired
    PersonService personService;

    private MockMvc mockMvc;

    @Configuration
    static class Config 
        // Other beans
        @Bean
        public PersonService getPersonService() 
            return mock(PersonService.class);
        
    
    @Test
    public void testPeople() throws Exception 
        // When
        ResultActions actions = mockMvc.perform(get("/people"));
    

我想运行mockMvc时出错

java.lang.NullPointerException

【问题讨论】:

mockMvc 是什么? @Ravi 服务器端 Spring MVC 测试的主要入口点 你能分享这门课吗? 【参考方案1】:

执行以下步骤:

    创建服务模拟而不是服务原始 (“PersonServiceMock”)

    用服务模拟替换服务原始

        @Autowired
        PersonService personService;
    
        @Autowired
        PeopleController peopleController;
    
        private MockMvc mockMvc;
    
        @Before
        public void setup() 
        peopleController = new PeopleController(new personServiceMock());
        mvc = MockMvcBuilders.standaloneSetup(peopleController).build();
           
    
        @Configuration
        static class Config 
            // Other beans
            @Bean
            public PersonService getPersonService() 
                return mock(PersonService.class);
            
        
        @Test
        public void testPeople() throws Exception 
            // When
            ResultActions actions = mockMvc.perform(get("/people"));
        
    
    

【讨论】:

【参考方案2】:

那是因为您从未在代码中初始化mockMvc,而您访问它的点会导致nullPointerException。您需要在使用它之前对其进行初始化,并且由于您的类中的多个测试可能正在使用它,因此最好的方法是使用带有@before 注释的setup() 方法。试试下面:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class PeopleControllerTest 
@Autowired
PersonService personService;

@Autowired
private WebApplicationContext wac;

private MockMvc mockMvc;

@Before
public void setup() 
  mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();


@Configuration
static class Config 
    // Other beans
    @Bean
    public PersonService getPersonService() 
        return mock(PersonService.class);
    

@Test
public void testPeople() throws Exception 
    // When
    ResultActions actions = mockMvc.perform(get("/people"));


【讨论】:

【参考方案3】:

从源代码中我看到 mockMvc 没有任何价值,这就是为什么它在这行代码中命中“java.lang.NullPointerException”:

ResultActions actions = mockMvc.perform(get("/people"));

为了让它运行,我认为首先需要为 mockMvc 赋予价值。 通过构造函数:

@Test
public void testPeople() throws Exception 
    mockMvc = new MockMvc();
    // When
    ResultActions actions = mockMvc.perform(get("/people"));

或自动接线:

@Autowired
MockMvc mockMvc

取决于 MockMvc 类的用途

【讨论】:

以上是关于通过模拟服务进行弹簧控制器测试的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 MockMvc 测试弹簧控制器方法?

junit中的模拟休息服务(带弹簧)

无法 POST 到 Mule 控制台模拟服务

为啥弹簧测试失败,不起作用@MockBean

在测试控制器方法时,Spring MVC 4.2.6 版似乎没有将模拟服务注入控制器

如何在 Service 构造函数中对 Controller 进行单元测试和模拟 @InjectModel