最近看到有人在Infoq写了用Jruby为Java写测试用例,
感觉不错,脚本语言的简便性得以充分发挥,于是不免手痒,尝试了一下,
Jruby虽好,却发现需要进行编译时出来诸多问题,比如java代码必须放入jruby的libpath下,
虽然不是什么大事,却无形中增加了推广难度,大家肯定会排斥做测试还需要这么麻烦的操作。
当然不是没有办法,不过似乎看上去很美的东西总是存在缺憾。
这个和Jruby不是Java原生支持的脚本有一定关系,于是想到了Groovy。
果然,尝试了一下Groovy后,发现其集成度远优于Jruby,
很简单的调用IDE中部署好的java类,无需任额外配置就可以run起来。
于是感觉找到了新路可走,深入挖掘,
单元测试最繁琐的事情当然属mock对象,一个代码中充斥了各种依赖的类,
这些类在正常的运行中又依赖于其他类和诸多环境变量和配置。
当然Groovy是个不错的语言,对于Junit的支持非常优秀,提供了MockFor和StubFor的方法来处理mock。
简单易懂,不过随着测试代码烦琐的深入,问题逐渐出现了。
我需要测试的一个业务类中,调用了一个读取配置的Util,
当然,除非我的运行环境全部run起来才有可能读取到这个配置,否则是读取不了的。
就是以为着我要mock这个读取配置的Util。
这个是个很典型的Groovy范例,我当时看了doc后是这样想的。
然而事实却远比我想象残酷,在我找遍了所有资料,尝试了n种做法后,
突然发现一个严重的问题,所有的例子里,你要mock的对象需要生效,比如是在groovy的脚本中才可以,
换句话说,我mock了一个util类,是的,我确实成功了,我在下面代码总这样使用
import groovy.mock.interceptor.MockFor
class JavaGroovyTest extends GroovyTestCase{
void firstTest(){
def mock = new MockFor(JavaUtil)
mock.demand.returnValue(1..2){false}//before mock, this return true
mock.use{
println(JavaUtil.retrunValue())
}
}
}
如我所料的返回了false,然而当这个util被包含在一个java类写的业务逻辑总,严重问题出现了,
groovy的mock无法使作用域进入class。
//java class, this is java code!
public class JavaClass
{
public boolean doReturnValue(){
return JavaUtil.returnValue();
}
}
import groovy.mock.interceptor.MockFor
class JavaGroovyTest extends GroovyTestCase{
void firstTest(){
def mock = new MockFor(JavaUtil)
mock.demand.returnValue(1..2){false}//before mock, this return true
mock.use{
def jc = new JavaClass()
println(jc.doReturnValue())
}
}
}
返回的值依旧是true,而且抛出一个异常:
junit.framework.AssertionFailedError: verify[0]: expected 1..2 call(s) to 'returnValue' but was called 0 time(s).
开始还没理解这个错误究竟怎么回事,后来发现,由于所调用的returnValue是在java的class中,
对于这个测试用例来说,根本就没有调到mock出来的returnValue方法,而这个方法要求至少被执行1-2次,
这个执行操作没有发生,因此就抛出了这个错。
如果mock根本就无法介入java的class,那么意味着使用Groovy的纯粹性大大下降,
我们写测试的话,必须把java和groovy混着写才行,我想没有一个公司的代码管理者希望看到这样的情况。
不知道有没有其他办法来解决这个问题,我暂时是没辙了,
感觉上想让脚本进入项目还有点时间。
感觉不错,脚本语言的简便性得以充分发挥,于是不免手痒,尝试了一下,
Jruby虽好,却发现需要进行编译时出来诸多问题,比如java代码必须放入jruby的libpath下,
虽然不是什么大事,却无形中增加了推广难度,大家肯定会排斥做测试还需要这么麻烦的操作。
当然不是没有办法,不过似乎看上去很美的东西总是存在缺憾。
这个和Jruby不是Java原生支持的脚本有一定关系,于是想到了Groovy。
果然,尝试了一下Groovy后,发现其集成度远优于Jruby,
很简单的调用IDE中部署好的java类,无需任额外配置就可以run起来。
于是感觉找到了新路可走,深入挖掘,
单元测试最繁琐的事情当然属mock对象,一个代码中充斥了各种依赖的类,
这些类在正常的运行中又依赖于其他类和诸多环境变量和配置。
当然Groovy是个不错的语言,对于Junit的支持非常优秀,提供了MockFor和StubFor的方法来处理mock。
简单易懂,不过随着测试代码烦琐的深入,问题逐渐出现了。
我需要测试的一个业务类中,调用了一个读取配置的Util,
当然,除非我的运行环境全部run起来才有可能读取到这个配置,否则是读取不了的。
就是以为着我要mock这个读取配置的Util。
这个是个很典型的Groovy范例,我当时看了doc后是这样想的。
然而事实却远比我想象残酷,在我找遍了所有资料,尝试了n种做法后,
突然发现一个严重的问题,所有的例子里,你要mock的对象需要生效,比如是在groovy的脚本中才可以,
换句话说,我mock了一个util类,是的,我确实成功了,我在下面代码总这样使用
import groovy.mock.interceptor.MockFor
class JavaGroovyTest extends GroovyTestCase{
void firstTest(){
def mock = new MockFor(JavaUtil)
mock.demand.returnValue(1..2){false}//before mock, this return true
mock.use{
println(JavaUtil.retrunValue())
}
}
}
如我所料的返回了false,然而当这个util被包含在一个java类写的业务逻辑总,严重问题出现了,
groovy的mock无法使作用域进入class。
//java class, this is java code!
public class JavaClass
{
public boolean doReturnValue(){
return JavaUtil.returnValue();
}
}
import groovy.mock.interceptor.MockFor
class JavaGroovyTest extends GroovyTestCase{
void firstTest(){
def mock = new MockFor(JavaUtil)
mock.demand.returnValue(1..2){false}//before mock, this return true
mock.use{
def jc = new JavaClass()
println(jc.doReturnValue())
}
}
}
返回的值依旧是true,而且抛出一个异常:
junit.framework.AssertionFailedError: verify[0]: expected 1..2 call(s) to 'returnValue' but was called 0 time(s).
开始还没理解这个错误究竟怎么回事,后来发现,由于所调用的returnValue是在java的class中,
对于这个测试用例来说,根本就没有调到mock出来的returnValue方法,而这个方法要求至少被执行1-2次,
这个执行操作没有发生,因此就抛出了这个错。
如果mock根本就无法介入java的class,那么意味着使用Groovy的纯粹性大大下降,
我们写测试的话,必须把java和groovy混着写才行,我想没有一个公司的代码管理者希望看到这样的情况。
不知道有没有其他办法来解决这个问题,我暂时是没辙了,
感觉上想让脚本进入项目还有点时间。
johnnyjian
2008/09/24 23:31
这是因为MockFor是通过MetaClass拦截了方法调用,而只有Groovy类才会通过MetaClass调用方法,Java类是直接调用方法的,也就是说Java写的方法调用无法被MockFor拦截。可以直接用Groovy的闭包mock方法(http://groovy.codehaus.org...),也可以用JMock或者EasyMock
分页: 1/1
[1]
[1]
最近又迷上seam了
RubyGems 1.3 fails on windows (undefined method `uid' for nil:NilClass)

2008/09/08 15:57 | by 