`

使用闭包替代Mock做测试

阅读更多
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 )
分享到:
评论
2 楼 macrochen 2010-08-22  
JohnnyJian 写道
引用
x = { f: {println "f called"} } as X

这个闭包在语法上是允许的,f是一个标签,{println "f called"}是一个被定义了但是没有被调用的闭包

我搞错了, 这个在语法上的确是可以的
1 楼 JohnnyJian 2010-08-19  
引用
x = { f: {println "f called"} } as X

这个闭包在语法上是允许的,f是一个标签,{println "f called"}是一个被定义了但是没有被调用的闭包

相关推荐

    C语言实现三种闭包算法(传递,自反,对称闭包)

    在C语言中实现这些闭包通常涉及到数组或链表等数据结构,用于存储关系,并使用迭代或递归方法来构建闭包。以下是可能的实现策略: 1. **传递闭包**:可以使用二维数组表示关系,然后遍历数组的每一行和每一列,每次...

    离散数学-关系,集合,求自反闭包,对称闭包,传递闭包

    离散数学-关系,集合,求自反闭包,对称闭包,传递闭包 离散数学-关系,集合,求自反闭包,对称闭包,传递闭包 离散数学-关系,集合,求自反闭包,对称闭包,传递闭包 离散数学-关系,集合,求自反闭包,对称闭包...

    Java闭包 Java闭包

    JSR-335 将闭包引入了 Java 。闭包在现在的很多流行的语言中都存在,例如 C++、C# 。闭包允许我 们创建函数指针,并把它们作为参数传递。在这篇文章中,将粗略的看一遍Java8的特性,并介绍 Lambda表达式。而且将试...

    计算NFA中ε闭包

    1. **数据结构定义**:使用结构体`edge`来表示一条边的信息,包括起点、终点和转换字符。 2. **输入函数**:`input()`函数负责接收用户输入,并根据输入构建NFA的数据结构。 3. **ε闭包计算**:`E_closure`函数...

    关系闭包的计算

    ### 关系闭包的计算 #### 实验背景与目的 在计算机科学与数学领域中,关系闭包是一种重要的概念,特别是在图论与数据库理论中有着广泛的应用。本实验旨在通过编程实践的方式帮助学习者深入理解关系闭包的概念,并...

    Swift闭包学习

    在Swift中,闭包的使用使得函数式编程风格得以实现,极大地增强了代码的灵活性和可读性。 首先,我们要了解闭包的基本语法。Swift中的闭包定义通常使用`{}`来包裹代码,参数和返回类型可选写。例如,一个简单的闭包...

    Swift之闭包ClosureDemo

    在"Swift之闭包ClosureDemo"中,可能会包含各种闭包的示例,如自定义排序、函数式编程的应用,或者在枚举和类中使用闭包等。通过这个Demo,你可以深入理解闭包如何与Swift的其他特性和设计模式相结合,提升代码的...

    求闭包 属性集闭包 函数依赖的闭包

    根据程序提示一步步往下做即可 1. 由用户输入函数依赖,当用户输入End时,表示所有依赖都输入完毕。(即函数依赖是由用户自己定的,程序中不能假定某个具体的依赖)。 2. 函数依赖的形式是ABC, ABE这样的形式,...

    JS闭包可被利用的常见场景

    // 使用闭包访问并调用对象的方法 obj[methodName](e); }; } // 创建一个对象实例 var myObject = { doOnClick: function(event) { /* 处理点击事件 */ }, doMouseOver: function(event) { /* 处理鼠标悬停...

    内存泄露,闭包 内存泄露,闭包 内存泄露,闭包

    4. 注意闭包的使用,确保在不再需要时释放对外部变量的引用。 总之,理解和掌握内存管理和闭包在JavaScript中的工作原理对于编写高效、无泄漏的代码至关重要。通过合理的设计、及时的解除引用以及有效的监控,可以...

    数据库求属性集闭包&函数依赖闭包

    声明:以下仅个人观点,若有错误,敬请指正O(∩_∩)O~ 关键点 1) 将函数依赖用multimap,string> 存储,因为函数依赖可能会有一对多,例如:A->X,A->Y;多重映射可以存储,一一映射只能能...最后做映射Rià(Ri+)j。

    最符合菜鸟的闭包

    比如,可以创建一个函数,返回一个新的函数,新函数记住其创建时的参数,这样每次调用新函数都会使用这些参数。 7. **事件处理**:在处理DOM事件时,闭包可以防止内部函数失去对事件源的引用,例如在循环中为多个...

    ios-闭包传值.zip

    本教程将深入探讨如何在iOS应用中使用闭包进行值传递。 闭包的基本语法: 闭包的语法通常由花括号 `{}` 包围,其中包含一组语句。闭包可以是匿名的,即没有名称,也可以通过类型别名或函数指针进行命名。在Swift中...

    JavaScript闭包函数

    闭包是ECMAScript (JavaScript)最强大的特性之一,但用...如果想要扬长避短地使用闭包这一特性,则必须了解它们的工作机制。而闭包工作机制的实现很大程度上有赖于标识符(或者说对象属性)解析过程中作用域的角色。

    js闭包个人理解

    ### JavaScript闭包的理解 在JavaScript中,闭包(Closure)是一种非常...然而,在实际开发过程中,我们也应该注意合理使用闭包,避免出现不必要的性能问题或内存泄漏。希望本文能对你理解JavaScript闭包有所帮助。

    js闭包详细讲解

    ### JavaScript闭包详解 #### 一、闭包概念与特性 **闭包**是JavaScript语言的一...总之,正确理解和使用闭包对于成为一名合格的JavaScript开发者至关重要。通过闭包,我们可以编写更加灵活、高效且易于维护的代码。

    Javascript 闭包完整解释

    ### JavaScript闭包完整...通过合理使用闭包,可以大大提高代码的灵活性和可维护性。然而,也需要警惕闭包可能导致的内存泄漏等问题。掌握闭包的工作原理及其应用,对于深入理解和高效开发JavaScript应用程序至关重要。

    用矩阵求自反闭包自反闭包

    在计算机科学和图论中,自反闭包是与关系理论相关的概念,特别是在布尔代数和图的子结构分析中。自反闭包是指给定一个关系R,将其扩展为包含所有起点到自身的元素对,即对于每一个元素a,都有(a, a)属于自反闭包。这...

    二元关系的闭包运算

    为了计算这些闭包,可以使用算法或者数学方法。例如,传递闭包可以通过Warshall算法来求解,这是一个简单的迭代过程,用于找出所有可能的传递路径。自反和对称闭包则相对直观,只需要直接添加对应的元素对即可。 ...

Global site tag (gtag.js) - Google Analytics