我正在尝试为我的控制器提供一个干净的单元测试。这个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注释。但为什么它会试图解决这个注释呢?这是假的吗?
答案 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.
}
}