概述
最近研究单元测试,在以前做单元测试的项目中都没用到spring框架,直接是用AspectJ将需要打桩的对象替换为mock对象。于是在这个项目中,也打算用AJ+mockito的方式来做打桩,结果却发现桩对象并没有被AJ替换掉,后来简单地单步跟了一下代码,发现AJ是在属性进行set的时候 触发aop,进行替换(这特么怎么和以前理解的AJ不一样啊,以前在eclipse下,貌似是直接静态编译的时候就替换掉了的,现在用intellij,不是这个原理了么?此外,就算编译的时候将有@Resource注解的属性替换了,但是后面还是可能被spring框架注入框架中的bean,于是放弃了这个方案)。
后来又尝试了Mockito的@InjectMocks注解,试了很多次,都没有成功。最后找到一篇文章(http://pwind.iteye.com/blog/1275159),需要自己实现一个TestExecutionListener
- public class MockitoDependencyInjectionTestExecutionListener extends DependencyInjectionTestExecutionListener {
- private static final Map<String, MockObject> mockObject = new HashMap<String, MockObject>();
- private static final List<Field> injectFields = new ArrayList<Field>();
- @Override
- protected void injectDependencies(final TestContext testContext) throws Exception {
- super.injectDependencies(testContext);
- init(testContext);
- }
- protected void injectMock(final TestContext testContext) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
- AutowireCapableBeanFactory beanFactory = testContext.getApplicationContext().getAutowireCapableBeanFactory();
- for (Field field : injectFields) {
- Object o = beanFactory.getBean(field.getName(), field.getType());
- if (null != o) {
- Method[] methods = o.getClass().getDeclaredMethods();
- for (Method method : methods) {
- if (method.getName().startsWith("set")) {
- for (Iterator it = mockObject.keySet().iterator(); it.hasNext();) {
- String key = (String) it.next();
- if (method.getName().equalsIgnoreCase("set" + key)) {
- method.invoke(o, mockObject.get(key).getObj());
- break;
- }
- }
- }
- }
- }
- }
- }
- private void init(final TestContext testContext) throws Exception {
- Object bean = testContext.getTestInstance();
- Field[] fields = bean.getClass().getDeclaredFields();
- for (Field field : fields) {
- Annotation[] annotations = field.getAnnotations();
- for (Annotation antt : annotations) {
- if (antt instanceof org.mockito.Mock) {
- // 注入mock实例
- MockObject obj = new MockObject();
- obj.setType(field.getType());
- obj.setObj(mock(field.getType()));
- field.setAccessible(true);
- field.set(bean, obj.getObj());
- mockObject.put(field.getName(), obj);
- } else if (antt instanceof Autowired) {
- // 只对autowire重新注入
- injectFields.add(field);
- }
- }
- }
- for (Field field : injectFields) {
- field.setAccessible(true);
- Object object = field.get(bean);
- if (object instanceof Proxy) {
- // 如果是代理的话,找到真正的对象
- Class targetClass = AopUtils.getTargetClass(object);
- if (targetClass == null) {
- // 可能是远程实现
- return;
- }
- Field[] targetFields = targetClass.getDeclaredFields();
- for (int i = 0; i < targetFields.length; i++) {
- // 针对每个需要重新注入的字段
- for (Map.Entry<String, MockObject> entry : mockObject.entrySet()) {
- // 针对每个mock的字段
- if (targetFields[i].getName().equals(entry.getKey())) {
- targetFields[i].setAccessible(true);
- targetFields[i].set(getTargetObject(object, entry.getValue().getType()),
- entry.getValue().getObj());
- }
- }
- }
- } else {
- injectMock(testContext);
- }
- }
- }
- protected <T> T getTargetObject(Object proxy, Class<T> targetClass) throws Exception {
- if (AopUtils.isJdkDynamicProxy(proxy)) {
- return (T) ((Advised) proxy).getTargetSource().getTarget();
- } else {
- return (T) proxy; // expected to be cglib proxy then, which is simply a specialized class
- }
- }
- public static class MockObject {
- private Object obj;
- private Class<?> type;
- public MockObject(){
- }
- public Object getObj() {
- return obj;
- }
- public void setObj(Object obj) {
- this.obj = obj;
- }
- public Class<?> getType() {
- return type;
- }
- public void setType(Class<?> type) {
- this.type = type;
- }
- }
- public static Map<String, MockObject> getMockobject() {
- return mockObject;
- }
- public static List<Field> getInjectfields() {
- return injectFields;
- }
- }
再在测试基类加上注解: @TestExecutionListeners
这样就不需要在执行单元测试之前执行MockitoAnnotations.initMocks(this)。
需要mock dao层的时候,就把repository抓出来,然后加上@InjectMocks注解,这样在单元测试启动的时候,就会将该测试中标注了@Mocks注解的mock对象注入到该bean中,完成属性替换。
最后
以上就是潇洒季节为你收集整理的在spring框架中,结合mockito打桩做单元测试的全部内容,希望文章能够帮你解决在spring框架中,结合mockito打桩做单元测试所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复