我试图为我的控制器提供一个干净的单元测试。这个控制器有一个服务作为依赖,而这个服务有一个数据源作为依赖。
测试如下:
@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注释。但它为什么要尝试解析这个注释呢?这是个玩笑吗?
Mockito确实使用cglib来创建MyService
的新子类(并使用mock方法覆盖所有方法)。
但是,父类的依赖项仍然会被注入,因为这就是Spring的工作方式:
如果你有一个父类有一些@Autowired
字段,并且子类继承了这个父类,那么Spring将在实例化子类时注入父类的@Autowired
字段。我猜你的情况也是一样的。
如果您使用MyService
的接口,那么您的问题将得到解决。
如果它应该是一个单元测试(而不是集成测试),您甚至不需要使用Spring,您可以使用JUnit+Mockito来完成所有工作。您可以简单地创建支持对象的模拟(通过@Mock
)并将它们注入测试对象(通过@InjectMocks
),而不是从Spring上下文中创建@Autowire
依赖项。我相信你的代码可以简化为这样的东西(概念上):
@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.
}
}