http://groovy.codehaus.org/Developer+Testing+using+Closures+instead+of+Mocks
觉得这篇文章对mock测试不错, 简单翻译一下.
在一些简单的测试场景下, 可以采用闭包加"as"关键字来实现我们需要mock的对象.
这种做法针对"面向接口编程"和"依赖注入"非常有效.
比如有这样的接口:
interface Logger { def log(message) }
interface Helper { def doSomething(param) }
interface Factory { Helper getInstance() }
有这样的实现类:
class MyApp {
private factory
private logger
MyApp(Factory factory, Logger logger) {
this.logger = logger this.factory = factory
}
def doMyLogic(param) {
factory.getInstance().doSomething(param)
logger.log('Something done with: ' + param)
}
}
具体用闭包的写法:
def param = 'DUMMY STRING'
def logger = { message -> assert message == 'Something done with: ' + param}
def helper = { assert it == param }
def factory = { helper as Helper }
def myApp = new MyApp(factory as Factory, logger as Logger)
myApp.doMyLogic(param)
只mock一个方法相对来说比较简单, 如果需要同时mock多个方法, 比如这种:
interface Helper {
def doSomething(param)
def doSomethingElse(param)
}
def doMyLogic(param) {
def helper = factory.getInstance()
helper.doSomething(param)
helper.doSomethingElse(param)
logger.log('Something done with: ' + param)
}
对于这种情况, 可以创建一个以要mock的方法为key, 以闭包为value的map, 然后将map as为指定的接口:
def helperMethod = { assert it == param }
def helper = [doSomething:helperMethod, doSomethingElse:helperMethod]
// as before
def factory = { helper as Helper }
如果两个方法执行同样的内容的话, 其实可以这样写:
def factory = { helperMethod as Helper }
延伸阅读:
http://groovy.codehaus.org/Groovy+way+to+implement+interfaces
这篇文章也不错, 用闭包代替接口
一个接口可以用闭包来实现:
// a readable puts chars into a CharBuffer and returns the count of chars added
def readable = { it.put("12 34".reverse()); 5 } as Readable
// the Scanner constructor can take a Readable
def s = new Scanner(readable)
assert s.nextInt() == 43
对于有多个方法的这样定义:
interface X
{ void f(); void g(int n); void h(String s, int n); }
x = {Object[] args -> println "method called with $args"} as X
x.f()
x.g(1)
x.h("hello",2)
那么接口的每一个方法被调用的时候都会执行闭包. 为了适应多个方法, 闭包中的参数使用了数组
更通用的做法是用map来模拟多个方法的情况:
impl = [
i: 10,
hasNext: { impl.i > 0 },
next: { impl.i-- },
]
iter = impl as Iterator
while ( iter.hasNext() )
println iter.next()
如果指定的方法为在map中没有对应的key, 那么会抛空指针异常
interface X
{ void f(); void g(int n); void h(String s, int n); }
x = [ f: {println "f called"} ] as X
x.f()
//x.g() // NPE here
下面是一种错误的写法:
x = { f: {println "f called"} } as X
x.f()
x.g(1)
因为这个是定义了一个闭包而不是一个map, 而且从groovy的语法来说也是不允许的.
更多的as用法, 可以看这里(
http://johnnyjian.iteye.com/blog/160796)
这里有一点需要注意, as的class类型必须是一个静态的引用, 否则是失败, 但是了动态指定as的具体类型, 也可以使用asType这样写:
def loggerInterface = Class.forName( 'my.LoggerInterface' )
def logger = [
log : { Object[] params -> println "LOG: ${params[0]}"; if( params.length > 1 ) params[1].printStackTrace() },
close : { println "logger.close called" }
].asType( loggerInterface )
分享到:
相关推荐
Shmock(SHorthand for MOCKing)是 PHPUnit 创建 mocks 的平稳替代,使用 EasyMock 的 mock/replay 概念,但是又使用 mocking 定义的闭包范围。 示例代码: <?php namespace Foo; /** * Here's a ...
10. **模拟与 spies**:在单元测试中,模拟(mock)和间谍(spy)用于替代真实对象或监控函数调用,以隔离被测试代码。 11. **覆盖率报告**:工具如Istanbul可以生成代码覆盖率报告,确保测试覆盖了足够多的代码...
本篇文章将深入探讨如何使用Mockery设置“闭包期望”(Closure Expectations),以实现更精确的测试。 首先,理解Mockery的基本概念至关重要。Mockery提供了一个简洁的API,用于创建模拟对象(mock objects)和期待...
此外,"Monkey"还可能是对某个功能或者对象的命名,比如模拟对象(Mock Object)库,用于单元测试中替代真实对象,以便隔离测试环境。JavaScript社区中有许多这样的工具,如Sinon.js,它可以创建模拟函数、对象和...
这样做的好处是组件的测试变得容易,因为可以使用mock对象来替换真实的依赖进行测试。同时,这种模式还便于后期的维护和扩展。 自学实现AngularJS依赖注入涉及几个重要的步骤,首先是创建一个简单的缓存来保存服务...