我们的系统中有许多控制器和许多Spring数据存储库。
我想为运行在MVC上下文中的控制器编写测试。
然而,必须手动模拟系统中的每个服务和存储库,这样我就可以测试控制器,这似乎很麻烦,而且是不对的
例如
FooControllerTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextHierarchy(value = {
@ContextConfiguration(classes = { MockServices.class }),
@ContextConfiguration({ "classpath:/META-INF/spring/mvc-servlet-context.xml" }),
})
public class FooControllerTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mvc;
@Autowired
private FooRepository fooRepository;
@Autowired
private FooService fooService;
@Before
public void setUp() throws Exception {
mvc = webAppContextSetup(wac).build();
}
@Test
public final void list() {
when(fooRepository.findAll()).thenReturn(...);
mvc.perform(get("/foo"))...
}
@Test
public final void create() {
Foo fixture = ...
when(fooService.create(fixture)).thenReturn(...);
mvc.perform(post("/foo"))...
}
}
MockServices.java
@Configuration
public class MockServices {
@Bean
public FooRespository fooRepositiory() {
return Mockito.mock(FooRespository.class);
}
@Bean
public FooService fooService() {
return Mockito.mock(FooService.class);
}
//even though we are "only" testing FooController, we still need to mock BarController's dependencies, because BarController is loaded by the web app context.
@Bean
public BarService barService() {
return Mockito.mock(FooService.class);
}
//many more "mocks"
}
我真的不想使用standaloneSetup()
(想使用生产配置,例如转换服务、错误处理程序等)
这只是我写控制器测试的代价吗?
似乎应该有类似mock every class annotated with @Service
或mock every interface that extends JpaRepository
的
MVC控制器的实现通常类似于将模型与视图集成的粘合代码。例如,当从控制器调用EJB,然后更新视图模型时。
因此,当您模拟所有依赖项并验证此集成或"粘合代码"是否按预期工作时,控制器测试可能会有意义。一般来说,如果集成测试意味着太多的组件,那么整个sut的模块化可能是系统真正可测试的必要条件。
无论如何,如果您觉得集成测试很费力,也许您可以尝试获得每个独立组件的最大覆盖率,并让功能测试获得Controller覆盖率。