2011年7月29日,关于使用mock来增加插件测试覆盖率
昨天和今天主要focus在这件事情上,但是还是没有找到比较好的方法。
插件的测试使用的是swtbot,内置junit的插件。
而mock主要类似stub的工作模式,用来模拟在unit test过程中,需要使用但是有没有办法拿到的一些对象。
我主要研究了一下easymock和powermock。powermock基于easymock实现,主要对easymock无法实现的静态方法,内部类,构造类等等方法的补充和实现。
esaymock的官网为:http://www.easymock.org/
我使用的是当前最新版本3.0,从官网上可以下载到最新的源码、jar包和文档,文档有详细的教程,同时诸多网站上有中文版本,整体比较简单,所以不加赘述。
需要说明的是jar包的问题,easymock本身不依赖于junit,但是运行时大多数都是在做测试,所以easymock.jar和junit.jar可以保证没有编译错误,但是运行时依然不好用,原因是它通过修改jvm中类的字节码实现mock,因此它依赖cglib-nodeep-2.2.jar和javassist.jar包。网上可以找到,是Jboss等第三方写的对字节码操作的基本类库。
官网描述如下
EasyMock only works with Java 1.5.0 and above.
cglib (2.2) and Objenesis (1.2) must be in the classpath to perform class mocking
powermock基于easymock实现,主要对easymock不能实现的类和方法的支持。
官网为:http://code.google.com/p/powermock/
它对Junit和testNG都有支持,同时也可以基于Mockito而不基于easymock。因为我使用的是junit的测试方法,所以研究了一下关于基于easymock的实现。
首先jar包问题
powermock实现了通过maven做依赖管理,因此可以直接把官网上的maven的信息copy到你的maven配置文件中,就可以拿到想要的jar包。
如果不依赖maven的话,官网上有可以下载的整体的zip包,主要包括几项内容:
easymock及其依赖的cglib和javassist,junit包,objenesis包(用于实现实例化类...),powermock自己的jar包
需要说明的是,powermock对版本的控制很严格,比如我下载的1.49版本的powermock,依赖3.0版本的easymock,1.2版本的objenesis,还依赖4.8.2版本的junit。
版本依赖比较严格,尤其是junit的jar包,4.8.1都有可能会导致不好用。
关于使用,
使用powermock主要是对easymock的弥补,实现静态方法、内部类、构造方法的mock。因此使用的时候主要注意两点,其余都和easymock没有区别。
1,使用@RunWith(runner....) 2, 使用 @PrepareForTest(***.class)
接下来进入正题,关于插件和powermock的协作。
首先
插件一般是用junit plugin test和swtbot协作完成非图形化和图形化的测试。这两种方式都是通过插件提供给用户使用的,意味着,它会附加junit插件,也意味着,它也是和junit版本绑定的。
swtbot针对当前版本的eclipse提供的有
eclipse version , junit version
3.5 4.5
3.6\3.7 4.81
然后powermock对junit版本依赖为:
powermock junit
1.49 4.82
1.4 4.81
从上述可以看出,我们只要使用3.6\3.7的eclipse安装swtbot插件,然后使用powermock的1.4版本就可以解决问题。
但是事实往往不是这样的。
假设我们已经完成上述版本的eclipse平台的搭建,那么,运行的时候就会有一个问题,
@RunWith()的参数,
swtbot的参数是@RunWith(SWTBotJunit4ClassRunner.class)
powermock的参数是@RunWith(PowerMockRunner.class)
解决这个问题,powermock提供了rule的方式调用,这是基于junit的rule实现的。
也就是不适用@RunWith(PowerMockRunner.class),而在类的开始声明一个变量替代runner方式运行。
@Rule
public PowerMockRule rule = new PowerMockRule();
OK,这个问题也解决了,正常可以运行了吧。
这么说可以说对,也可以说不对。因此这样的方式,在普通的java项目中,已经可以实现,rule替代runner的方式,按照rule方式完全可以正确的运行测试用例。这提供了便利,比如说对于spring来说,可以既使用自己的runner也可以使用powermock,这点在官网上有相应的链接。
但是这种方式对插件来说依然不好使。
现象:
在插件项目中,运行普通项目好使的powermock rule用例,会抛出异常,去掉依赖的junit4插件,添加需要的4.82版本的junit类路径,按照junit test方式运行,可以工作。但是添加swtbot的runner按照swtbot方式运行,不好使。
分析:因为我测试使用的是eclipse 3.5也就是使用的junit 插件中junit的版本为4.5,powermock的rule最少运行在powermock的1.4版本上,也就是要求junit最少为4.81。
另一点就代表了,swtbot对junit插件是强依赖,也就是必须加入这项插件依赖,不然就会抛出no runner的异常。
于是,我换了eclipse,3.6和3.7版本都测试了。
{
3.6现象:
使用powermock runner方式编写,junit test运行,正常工作。
使用powermock rule方式编写,junit test方式运行报java.lang.NoSuchMethodError: org.powermock.api.support.ClassLoaderUtil.loadClass(Ljava/lang/String;)Ljava/lang/Class异常。
()
而且无论我使用自己添加还是junit4插件中的juint 4.8.1,都会抛出这个异常。
3.7现象
使用powermock runner方式编写,junit test运行,正常工作。
使用powermock rule方式编写,junit test方式运行,正常工作。
使用powermock rule方式编写,swtbot test方式运行,抛出异常。
原因是什么?(我没有细致的去研究swtbot和powermock的源码,有些内容分析可能不正确)
我认为是junit版本的冲突,以及插件的类加载问题。
版本冲突可以解决。
类加载问题比较复杂,3.6一直抛出类加载异常,3.7则一直是assert异常。具体原因不详。
而插件运行状态的时候的运行时的classloader和load插件中的类的classloader是两个(这是一种原因)
}
上面测试出问题了,原因是powermock rule模式所依赖的几个jar包也是有版本问题的。
这是这两天的测试结果。
OK,继续说上述话题。
测试数据有误,懒得改上面,直接加在下面。
powermock rule方式
eclipse swtbot_junit powermock_junit powermock
3.5 4.5 4.82 1.49
添加powermock的jar包到编译路径和运行时,同时配置好swtbot所需的依赖插件,junit test方式run ,抛出异常_java.lang.IllegalStateException: no last call on a mock available
把plugin.xml中的junit4的插件删除,junit test方式run 好使
但是,按照swtbot test方式运行,抛出异常 java.lang.Exception: No runnable methods
不删除plugin.xml中的junit4的插件,抛出异常java.lang.NoClassDefFoundError: org/powermock/modules/junit4/rule/PowerMockRule
分析,因为swtbot_junit和powermock_junit版本不一致导致,插件会优先加载swtbot_junit,但是swtbot_junit的版本不足够满足powermock需求。另外,swtbot和powermock对junit版本有比较强的依赖。@RunWith属性似乎对于运行时的swtbot没有影响,因为无论有没有都会报NoClassDefFoundError异常。
powermock rule方式
eclipse swtbot_junit JDT_Junit powermock_junit powermock
3.6 4.81 4.82 4.81 1.47
添加powermock的jar包到编译路径和运行时,同时配置好swtbot所需的依赖插件,junit test方式run ,不删除junit4插件依赖,好使。删除也好使。
按照swtbot test方式运行,java.lang.ClassNotFoundException: org.easymock.internal.LastControl
我看了一下easymock中,有这个类,那就是加载类的问题了。
现在麻烦在于swtbot、JDT、powermock都有对Junit的依赖,首先是加载容器的问题,其次是加载顺序的问题。
插件的测试使用的是swtbot,内置junit的插件。
而mock主要类似stub的工作模式,用来模拟在unit test过程中,需要使用但是有没有办法拿到的一些对象。
我主要研究了一下easymock和powermock。powermock基于easymock实现,主要对easymock无法实现的静态方法,内部类,构造类等等方法的补充和实现。
esaymock的官网为:http://www.easymock.org/
我使用的是当前最新版本3.0,从官网上可以下载到最新的源码、jar包和文档,文档有详细的教程,同时诸多网站上有中文版本,整体比较简单,所以不加赘述。
需要说明的是jar包的问题,easymock本身不依赖于junit,但是运行时大多数都是在做测试,所以easymock.jar和junit.jar可以保证没有编译错误,但是运行时依然不好用,原因是它通过修改jvm中类的字节码实现mock,因此它依赖cglib-nodeep-2.2.jar和javassist.jar包。网上可以找到,是Jboss等第三方写的对字节码操作的基本类库。
官网描述如下
EasyMock only works with Java 1.5.0 and above.
cglib (2.2) and Objenesis (1.2) must be in the classpath to perform class mocking
powermock基于easymock实现,主要对easymock不能实现的类和方法的支持。
官网为:http://code.google.com/p/powermock/
它对Junit和testNG都有支持,同时也可以基于Mockito而不基于easymock。因为我使用的是junit的测试方法,所以研究了一下关于基于easymock的实现。
首先jar包问题
powermock实现了通过maven做依赖管理,因此可以直接把官网上的maven的信息copy到你的maven配置文件中,就可以拿到想要的jar包。
如果不依赖maven的话,官网上有可以下载的整体的zip包,主要包括几项内容:
easymock及其依赖的cglib和javassist,junit包,objenesis包(用于实现实例化类...),powermock自己的jar包
需要说明的是,powermock对版本的控制很严格,比如我下载的1.49版本的powermock,依赖3.0版本的easymock,1.2版本的objenesis,还依赖4.8.2版本的junit。
版本依赖比较严格,尤其是junit的jar包,4.8.1都有可能会导致不好用。
关于使用,
使用powermock主要是对easymock的弥补,实现静态方法、内部类、构造方法的mock。因此使用的时候主要注意两点,其余都和easymock没有区别。
1,使用@RunWith(runner....) 2, 使用 @PrepareForTest(***.class)
接下来进入正题,关于插件和powermock的协作。
首先
插件一般是用junit plugin test和swtbot协作完成非图形化和图形化的测试。这两种方式都是通过插件提供给用户使用的,意味着,它会附加junit插件,也意味着,它也是和junit版本绑定的。
swtbot针对当前版本的eclipse提供的有
eclipse version , junit version
3.5 4.5
3.6\3.7 4.81
然后powermock对junit版本依赖为:
powermock junit
1.49 4.82
1.4 4.81
从上述可以看出,我们只要使用3.6\3.7的eclipse安装swtbot插件,然后使用powermock的1.4版本就可以解决问题。
但是事实往往不是这样的。
假设我们已经完成上述版本的eclipse平台的搭建,那么,运行的时候就会有一个问题,
@RunWith()的参数,
swtbot的参数是@RunWith(SWTBotJunit4ClassRunner.class)
powermock的参数是@RunWith(PowerMockRunner.class)
解决这个问题,powermock提供了rule的方式调用,这是基于junit的rule实现的。
也就是不适用@RunWith(PowerMockRunner.class),而在类的开始声明一个变量替代runner方式运行。
@Rule
public PowerMockRule rule = new PowerMockRule();
OK,这个问题也解决了,正常可以运行了吧。
这么说可以说对,也可以说不对。因此这样的方式,在普通的java项目中,已经可以实现,rule替代runner的方式,按照rule方式完全可以正确的运行测试用例。这提供了便利,比如说对于spring来说,可以既使用自己的runner也可以使用powermock,这点在官网上有相应的链接。
但是这种方式对插件来说依然不好使。
现象:
在插件项目中,运行普通项目好使的powermock rule用例,会抛出异常,去掉依赖的junit4插件,添加需要的4.82版本的junit类路径,按照junit test方式运行,可以工作。但是添加swtbot的runner按照swtbot方式运行,不好使。
分析:因为我测试使用的是eclipse 3.5也就是使用的junit 插件中junit的版本为4.5,powermock的rule最少运行在powermock的1.4版本上,也就是要求junit最少为4.81。
另一点就代表了,swtbot对junit插件是强依赖,也就是必须加入这项插件依赖,不然就会抛出no runner的异常。
于是,我换了eclipse,3.6和3.7版本都测试了。
{
3.6现象:
使用powermock runner方式编写,junit test运行,正常工作。
使用powermock rule方式编写,junit test方式运行报java.lang.NoSuchMethodError: org.powermock.api.support.ClassLoaderUtil.loadClass(Ljava/lang/String;)Ljava/lang/Class异常。
()
而且无论我使用自己添加还是junit4插件中的juint 4.8.1,都会抛出这个异常。
3.7现象
使用powermock runner方式编写,junit test运行,正常工作。
使用powermock rule方式编写,junit test方式运行,正常工作。
使用powermock rule方式编写,swtbot test方式运行,抛出异常。
原因是什么?(我没有细致的去研究swtbot和powermock的源码,有些内容分析可能不正确)
我认为是junit版本的冲突,以及插件的类加载问题。
版本冲突可以解决。
类加载问题比较复杂,3.6一直抛出类加载异常,3.7则一直是assert异常。具体原因不详。
而插件运行状态的时候的运行时的classloader和load插件中的类的classloader是两个(这是一种原因)
}
上面测试出问题了,原因是powermock rule模式所依赖的几个jar包也是有版本问题的。
这是这两天的测试结果。
OK,继续说上述话题。
测试数据有误,懒得改上面,直接加在下面。
powermock rule方式
eclipse swtbot_junit powermock_junit powermock
3.5 4.5 4.82 1.49
添加powermock的jar包到编译路径和运行时,同时配置好swtbot所需的依赖插件,junit test方式run ,抛出异常_java.lang.IllegalStateException: no last call on a mock available
把plugin.xml中的junit4的插件删除,junit test方式run 好使
但是,按照swtbot test方式运行,抛出异常 java.lang.Exception: No runnable methods
不删除plugin.xml中的junit4的插件,抛出异常java.lang.NoClassDefFoundError: org/powermock/modules/junit4/rule/PowerMockRule
分析,因为swtbot_junit和powermock_junit版本不一致导致,插件会优先加载swtbot_junit,但是swtbot_junit的版本不足够满足powermock需求。另外,swtbot和powermock对junit版本有比较强的依赖。@RunWith属性似乎对于运行时的swtbot没有影响,因为无论有没有都会报NoClassDefFoundError异常。
powermock rule方式
eclipse swtbot_junit JDT_Junit powermock_junit powermock
3.6 4.81 4.82 4.81 1.47
添加powermock的jar包到编译路径和运行时,同时配置好swtbot所需的依赖插件,junit test方式run ,不删除junit4插件依赖,好使。删除也好使。
按照swtbot test方式运行,java.lang.ClassNotFoundException: org.easymock.internal.LastControl
我看了一下easymock中,有这个类,那就是加载类的问题了。
现在麻烦在于swtbot、JDT、powermock都有对Junit的依赖,首先是加载容器的问题,其次是加载顺序的问题。
> 我来回应
热门话题 · · · · · · ( 去话题广场 )
- 想做的事,别等“以后”1.0万+篇内容 · 432.1万次浏览
- 让人生变开阔的方法1.0万+篇内容 · 20.1万次浏览
- 端午吃什么1207篇内容 · 22.6万次浏览
- 重新养一遍自己,可真好啊1786篇内容 · 234.2万次浏览
- 哪个瞬间你发现自己被琐碎地爱着?298篇内容 · 93.0万次浏览
- 假期必备书影音清单489篇内容 · 30.4万次浏览
- 你有哪些“终不似,少年游”的经历?3061篇内容 · 75.6万次浏览
- 端午去哪儿572篇内容 · 11.2万次浏览