Spring MVC中的模拟服务

时间:2017-08-21 11:23:17

标签: spring testing spring-boot mocking mockito

我在Spring MVC中遇到了模拟服务的问题:

@Controller
public class CompanyController {

  @Autowired
  private CompanyService companyService;

  @Autowired
  private CompanyRelationService companyRelationService;

  @GetMapping({"/", "/companies"})
  public String displayCompanies(Model model) {
    model.addAttribute("company", new Company());
    List<Company> companies = companyService.findAll();
    model.addAttribute("companies", companies);
    return "companies";
  }
}

并测试:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class CompanyTests {

@Autowired
private WebApplicationContext webApplicationContext;

@Mock
CompanyService companyServiceMock;

private MockMvc mockMvc;


@Before
public void setUp() {
    Mockito.reset(companyServiceMock);
    mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    MockitoAnnotations.initMocks(this);
}


@Test
public void shouldListAllCompanies() throws Exception {
    Company company1 = new Company("company1", new Address());
    Company company2 = new Company("company2", new Address());

    when(companyServiceMock.findAll()).thenReturn(Arrays.asList(company1, company2));

    mockMvc.perform(get("/companies"))
            .andExpect(status().isOk())
            .andExpect(view().name("companies"))
            .andExpect(model().attribute("companies", hasSize(2)))
            .andExpect(model().attribute("companies", hasItem(
                    allOf(
                            hasProperty("name", is("company1")))
            )))
            .andExpect(model().attribute("companies", hasItem(
                    allOf(
                            hasProperty("name", is("company2"))
                    )
            )));

}
}

问题是为什么我从实际服务而不是模拟(company1,company2)获得公司:

java.lang.AssertionError: Model attribute 'companies'
     Expected: a collection containing (hasProperty("name", is "company1"))
     but: hasProperty("name", is "company1") property 'name' was "companyFromRealService", 
     hasProperty("name", is "company1") property 'name' was "CompanyFromRealService2"

更新了Test类,删除了setUp并将@Bean更改为@MockBean,但保留@SpringBootTest并且它可以工作:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class CompanyTests {

@MockBean
private CompanyService companyServiceMock;

@Autowired
private MockMvc mockMvc;

@Test
@WithMockUser(roles = "ADMIN")
public void shouldListAllCompanies() throws Exception {
    Company company1 = new Company("company1", new Address());
    Company company2 = new Company("company2", new Address());

    when(companyServiceMock.findAll()).thenReturn(Arrays.asList(company1, company2));

    mockMvc.perform(get("/companies"))
            .andExpect(status().isOk())
            .andExpect(view().name("companies"))
            .andExpect(model().attribute("companies", hasSize(2)))
            .andExpect(model().attribute("companies", hasItem(
                    allOf(
                            hasProperty("name", is("companyFromRealService1")))
            )))
            .andExpect(model().attribute("companies", hasItem(
                    allOf(
                            hasProperty("name", is("companyFromRealService2"))
                    )
            )));
}

}

1 个答案:

答案 0 :(得分:2)

首先,如果您只是测试应用程序的控制器切片,则应使用@WebMvcTest注释而不是@SpringBootTest(您可以找到更多信息here)。您可以像这样使用它:@WebMvcTest(CompanyController.class)

其次,您为什么在MockMvc方法中遇到setUp()问题?您可以删除人们在评论和setUp MockMvc中建议的@Autowire方法。

最后,当您使用spring boot时,最好使用@MockBean而不是@Mock,它是弹簧库中的包装版本。