使用Spring 3.2和Mockito进行控制器单元测试的上下文初始化问题

时间:2013-04-10 12:56:32

标签: java spring-mvc mockito

我正在尝试为我的控制器提供一个干净的单元测试。这个Controller有一个Service作为依赖,这个Serviceh有一个Datasource作为依赖。

测试如下:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class ContentActionWebServiceControllerTest {
  @Autowired
  private WebApplicationContext wac;

  private MockMvc mockMvc;

  @Autowired
  private MyService myService;

  @Test
  public void getRequestActionList() throws Exception {
    when(...)
    perform(...);
    verify(...);
  }

  @Configuration
  @ImportResource("...")
  static class MyTestConfiguration {

    @Bean
    public MyService myService() {
      return Mockito.mock(MyService.class);
    }
  }
}

MyService就像

@Service
public class MyService {
  @Autowired
  private MyDataSource myDatasource;

  ...
}

因为MyService是一个Autowired属性MyDataSource,所以没有初始化上下文,因为它没有找到任何MyDataSource类型来满足MyService的@Autowired注释。但为什么它会试图解决这个注释呢?这是假的吗?

2 个答案:

答案 0 :(得分:4)

Mockito确实使用cglib创建了一个MyService的新子类(并使用模拟方法覆盖所有方法)。

但是,仍然会注入父项的依赖项,因为这就是Spring的工作方式:

如果你有一个带有一些@Autowired字段的父类,以及一个继承自这个父类的子类,那么Spring会在实例化子进程时注入父进程的@Autowired字段。我猜你的情况也是如此。

如果您使用MyService的界面,那么您的问题就会得到解决。

答案 1 :(得分:1)

如果它应该是一个单元测试(而不是集成测试),你甚至不需要使用Spring,你可以使用JUnit + Mockito完成所有操作。您可以简单地创建支持对象的模拟(通过@Autowire)并将其注入受测者(通过@Mock),而不是@InjectMocks来自Spring上下文的依赖项。我相信你的代码可以简化为(概念上)这样的东西:

@RunWith(MockitoJUnitRunner.class)
public class ContentActionWebServiceControllerTest {

  @Mock
  private Service mockServiceUsedByController;

  @InjectMocks
  private YourController testee;

  @Test
  public void getRequestActionList() throws Exception {
    assertFalse(testee.getRequestActionList().isEmpty());
    // etc.
  }
}