【问题标题】:Spring MVC Controller testing, and mocking many classesSpring MVC Controller 测试和模拟许多类
【发布时间】:2014-10-20 22:43:27
【问题描述】:

我们的系统中有许多控制器,以及许多 Spring Data 存储库。

我想为通过我的 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 @Servicemock every interface that extends JpaRepository之类的东西

【问题讨论】:

  • 在控制器测试中,您是否可以简单地执行 @Mock YourService service 并将其设置在您的控制器上并期望/验证您的模拟服务?这样,存储库根本不会发挥作用(因为那不是您正在测试的东西)
  • mvc-servlet-context.xml 有一个component-scan,它实例化了系统中的所有控制器。控制器有@Autowire's 到各种服务和/或存储库。测试FooController 仍然需要你模拟BarController 中使用的BarService
  • 我已经更新了我的sn-ps,但是想多了,我想要的可能是不可能的。
  • 我假设当您说“手动”时,您的意思是在 MockServices 中添加一个附加方法。我不认为这是一个很大的开销(只要您的测试对您有用)。但是,我会非常简单地通过简单地关注控制器而不担心 WebAppConfiguration、xml 等(并不是说你的方法是错误的)。您可以在控制器测试中简单地 @Mock YourService 服务,而不是编写和更新 MockServices。如果设置服务有问题,您可以自动装配接收服务的控制器构造函数。希望对您有所帮助!
  • 您想要的可以使用不同的模拟工具 JMockit(我开发的)来完成。您只需要声明注解为@Capturing 的模拟字段,这样Spring 实例化的实现类就会被模拟。

标签: java spring spring-mvc mockito


【解决方案1】:

MVC 控制器的实现通常类似于将模型与视图集成在一起的胶水代码。例如,从 Controller 调用 EJB 然后更新 View 模型时。

因此,当您确实模拟所有依赖项并验证此集成或“粘合代码”是否按预期工作时,可能会进行控制器测试。一般来说,如果集成测试包含太多组件,则可能需要对整个组件进行模块化才能使系统实际可测试。

无论如何,如果您觉得集成测试很费力,也许您可​​以尝试让每个独立组件的覆盖率最大化,让功能测试获得 Controller 覆盖率。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多