`
wh870712
  • 浏览: 40623 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

使用闭包代替Mock测试

阅读更多
在一些简单的测试场景下, 可以采用闭包加"as"关键字来实现我们需要mock的对象.
这种做法针对"面向接口编程"和"依赖注入"非常有效.
比如有这样的接口:
Java代码
interface Logger { def log(message) }   
interface Helper { def doSomething(param) }   
interface Factory { Helper getInstance() }  

interface Logger { def log(message) }
interface Helper { def doSomething(param) }
interface Factory { Helper getInstance() }
有这样的实现类:
Java代码
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)  
    }  


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)
    }
}

具体用闭包的写法:
Java代码
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) 

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多个方法, 比如这种:
Java代码
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)  
    } 

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为指定的接口:
Java代码
def helperMethod = { assert it == param }  
def helper = [doSomething:helperMethod, doSomethingElse:helperMethod]  
// as before  
def factory = { helper as Helper } 

def helperMethod = { assert it == param }
def helper = [doSomething:helperMethod, doSomethingElse:helperMethod]
// as before
def factory = { helper as Helper }

如果两个方法执行同样的内容的话, 其实可以这样写:
Java代码
def factory = { helperMethod as Helper } 

def factory = { helperMethod as Helper }

延伸阅读:
http://groovy.codehaus.org/Groovy+way+to+implement+interfaces
这篇文章也不错, 用闭包代替接口

一个接口可以用闭包来实现:
Java代码
// 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 

// 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

对于有多个方法的这样定义:
Java代码
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) 

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来模拟多个方法的情况:
Java代码
impl = [  
  i: 10,  
  hasNext: { impl.i > 0 },  
  next: { impl.i-- },  
]  
iter = impl as Iterator  
while ( iter.hasNext() )  
  println iter.next() 

impl = [
  i: 10,
  hasNext: { impl.i > 0 },
  next: { impl.i-- },
]
iter = impl as Iterator
while ( iter.hasNext() )
  println iter.next()

如果指定的方法为在map中没有对应的key, 那么会抛空指针异常
Java代码
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 

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

下面是一种错误的写法:
Java代码
x = { f: {println "f called"} } as X  
x.f()  
x.g(1) 

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这样写:
Java代码
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 ) 
分享到:
评论

相关推荐

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

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

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

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

    Swift闭包学习

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

    Java闭包 Java闭包

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

    计算NFA中ε闭包

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

    关系闭包的计算

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

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

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

    Swift之闭包ClosureDemo

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

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

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

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

    3. 用户输入完毕所有的依赖后,显示“请输入属性集求闭包”的提示,当用户输入1个或者多个属性时,求出对应的闭包。(如,用户输入A,则显示A+的值, 用户输入AB则求出AB+的值。显示完毕后,再次显示“请输入属性集...

    JavaScript闭包函数

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

    ios-闭包传值.zip

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

    最符合菜鸟的闭包

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

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

    3) 计算属性集闭包的算法,在课件里有详细说明。方法很简单,但用文字描述很抽象。。。。不解释。。。 4) 计算函数依赖的闭包。此步骤不作要求,但要会方法。个人总结:将所有属性元素组成一个集合(域)记为R;...

    js闭包个人理解

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

    ios-Swift使用闭包实现类似于BlocksKit添加点击事件功能.zip

    ClosuresKit库就是这样一个工具,它允许我们用Swift的闭包来代替BlocksKit中的Block,实现对UIView及其子类的点击事件监听。使用ClosuresKit,我们不再需要手动实现UIControl的触控事件代理方法,如`touchesBegan(_:...

    js闭包详细讲解

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

    Javascript 闭包完整解释

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

    第020讲:函数:内嵌函数和闭包 _ 课后测试题及答案,《零基础入门学习Python》,Python交流,鱼C论坛 - Powered by Discuz!.html

    第020讲:函数:内嵌函数和闭包 _ 课后测试题及答案,《零基础入门学习Python》,Python交流,鱼C论坛 - Powered by Discuz!.html

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

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

Global site tag (gtag.js) - Google Analytics