我有这样的控制器
@Controller
public class MyController {
@Autowire
MyClass myClass;
//myClass doesn't have setter and getter
....
@RequestMapping("/path")
public String underTest(){
myClass.makeSomething();
return "html.jsp"
}
我想使用Mockito和mock-myClass进行模拟测试。在测试课上,我想得到myClass,所以:
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/BeanConfig.xml");
myClass = context.getBean("myClass ", MyClass .class);
但我需要将这个bean自动连接到Controller,以测试控制器的方法(我认为测试代码不应该影响正常代码)。
有没有不写集合方法的方法?
我想检查myClass.makeSomething()是否在方法underTest中调用过一次。
只要MyController
的测试与MyController
本身位于同一个包中(通常是在不同的源文件夹中的相同包中),您就可以简单地分配它:
MyController controller = new MyController();
controller.myClass = mockMyClass;
这就是不将@Inject
/@Autowired
放在private
字段上的原因。
我不确定我是否同意您的观点,即测试代码不应该影响正常代码。我认为重构/重写生产代码的一个完全合理的理由是使其更具可测试性(这可能是通过使其更模块化来实现的,这通常是一件好事)。
这正是像这样的注释的原因
@VisibleForTesting
存在。然后,您可以为MyClass创建一个包本地setter,添加上面的注释(供其他程序员和可能的代码检查工具参考),并在测试中设置字段(应该位于同一个包中)。
或者,由于您使用的是Mockito,您可以简单地用@InjectMocks注释MyController实例,例如
@Test
public class MyControllerTest {
@Mock
private MyClass mockMyClass;
@InjectMocks
private MyController myController;
@BeforeMethod
public void before() {
MockitoAnnotations.initMocks(this);
}
// do tests...
}
请注意,@InjectMocks不依赖于目标字段上的任何注释(即@Autowired、@Resource、@Inject等)。它只是起作用。(假设Spring注入仍然需要这些注释,所以不要删除它们!关键是,您还可以将其用于未注释的字段)。
还要注意的是,根据您使用的Mockito版本,在调用MockitoAnnotations.initMocks()之前,您可能需要在before()方法中实例化MyController
尝试使用context.getBean()直接测试控制器。MyClass将自动连接到其中。
我同意@axtavt的回答,但如果你绝对想在集成测试中注入mock,你可以这样做:
定义一个覆盖bean配置文件,比如bean-test-config.xml,内容如下:
<import resource="classpath:spring/BeanConfig.xml"/>
<bean name="myClass" factory-method="mock" class="org.mockito.Mockito">
<constructor-arg value="MyClass"></constructor-arg>
</bean>
这应该在控制器中正确地注入mock。您必须在测试中抓住这个mock,并注入您期望从这个mock中得到的任何行为。