`
ajoo
  • 浏览: 452732 次
社区版块
存档分类
最新评论
阅读更多
场景一:

个人喜欢state-based的单元测试。(定义见mock is not stub)。

可是有些时候,比如在测试一些使用java.sql.Connection, ibatis SqlMapClient等接口的类的时候,明显写stub很不好。(1,接口很大,有很多不相干的东西。2,版本一旦变化,这些接口可能跟着变化,如果写stub的话,就意味着stub要跟着这些第三方接口变化)

于是,只好mock。只好interaction based。只好每回内部实现一变就死盯着一坨坨的expectAndReturn找不再有效的expectation。

场景二:

一个遗留系统用自己的连接池,使用ConnectionManager.checkIn(Connection)来释放连接(而不是Connection.close)

为了重构,希望能够重载Connection.close(),让它调用checkIn()。

跟场景一的提到的原因一样,不希望直接写一个MyConnection implements Connection。于是只好自己写dynamic proxy,形成如下的代码:
  private Connection conn;
  public Object invoke(Object proxy, Method method, Object[] args){
    if((args==null || args.length==0) && method.getName().equals("close")){
      ConnectionManager.checkIn((Connection)conn);
    }
    else {
      try {
        return method.invoke(conn, args);
      }
      catch(InvocationTargetException e){
        throw e.getTargetException();
      }
    }
  }



后面又发现这个变态的一流系统居然用自己的startMyTransaction, endMyTransaction(), rollbackMyTransaction()来搞事务处理!
于是又要继续判断method.getName().equals("startTransaction"), method.getName().equals("commitTransaction")等等等等。

dynamic proxy的代码难看的要死。



最近终于受不了了。愤然写了一个叫做酒窝的东西(dimple)。

所谓dimple,就是dynamic implementor的意思。我要用纯java语法来实现我想实现的方法(不是expectAndReturn,也不是if(method.getName().equals("method1"))),但是同时我又不愿意写“implements TheInterface”,以避免被迫处理那些我不关心的method。

用法如下:

场景一:

这样实现我的stub:
MyParameter myparam = ...;
SqlMapClient client = (SqlMapClient) Implementor.proxy(SqlMapClient.class, new Object(){
  public Object insert(String id, Object param) {
    assertEquals("test id", id);
    assertSame(myparam, param);
    return null;
  }
});
assertNull(new SomeClassUsingSqlMapClient(client).runSomeInsert(myparam));


没有讨厌的expectAndReturn,不用担心parameter matcher。


场景二:
final Connection realConn = ...;
Connection conn = (Connection) Implementor.proxy(Connection.class, new Object(){
  public void close() {
    ConnectionManager.checkIn(realConn);
  }
  public void startTransaction(){
    ConnectionManager.startMyTransaction(realConn);
  }
  public void commitTransaction(){
    ConnectionManager.commitTransaction(realConn);
  }
}, realConn);

于是,对close(), startTransaction, commitTransaction(),我们都直接调用ConnectionManager, 而对其它的method则委托给realConn。




这个Implementor类是纯java代码,除了dynamic proxy没有用任何其它技术。(没有enhancement,aop之类的)



个人感觉还是挺有用的。大家点评一下?
分享到:
评论
51 楼 shaucle 2006-12-18  
俺还是很喜欢ajoo的这个,好用极了...而且符合30-70原则(还没到20-80),呵呵
50 楼 ajoo 2006-12-16  
场景一:
做stub。只实现一百个方法中的一个或者两个

场景二:
动态地仅仅intercept一个对象,而不是全局地针对一个类。


aspectj怎么做?既然就几行代码,写一下不是很容易?
49 楼 partech 2006-12-16  
俺还就是只想说说。
在interface上定义切点,用Proxy得到代理类,around想要处理的方法。
48 楼 floating 2006-12-16  
aspectJ支持在class loading的时候织入代码,但是还不支持在runtime时纯动态地织入。不过,我觉得ajoo举的这个例子,即使需要点动态的色彩,在class loading时能织入代码也应该可以满足需要了吧?
47 楼 ajoo 2006-12-16  
好啊。show一下aspectj怎么做这两个场景?
46 楼 partech 2006-12-16  
aspectJ也可以动态的,测试本来就是构件的一个方面(aspect),我看不出有什么充分的理由不能用。
45 楼 ajoo 2006-12-16  
aspectj和这个做的不同。它是静态的,而dimple是动态的。
另外你做测试的stub也用aspectj么?
44 楼 floating 2006-12-16  
问一下楼主为什么觉得采用aop的方式不好?用AspectJ来实现这个功能,就很简单的几句话啊。
43 楼 ajoo 2006-12-16  
项目搞定了。

http://dimple.codehaus.org


42 楼 ajoo 2006-12-14  
shaucle 写道
公司里不能上传

主要还是楼主的核心代码,

不过看起来稍有点层次感,提供一起扩展性,不会侵权吧,呵呵


我会用apache 2.0 license。你只要代码里保留我的注释,怎么改都行的。
41 楼 shaucle 2006-12-14  
公司里不能上传

主要还是楼主的核心代码,

不过看起来稍有点层次感,提供一起扩展性,不会侵权吧,呵呵
40 楼 shaucle 2006-12-14  
俺重写了一下

1 提出专门的对外接口.
public class Proxy {
   
    public static Object proxy(Object target, Object interceptor)

    public static Object proxy(Class asType, Object target, Object interceptor)

    public static Object proxy(Class asType, Object interceptor)

2 对于缓存中的Method新用一个对象(MethodKey)作为Key

3 对于dock优先级问题用strategy模式提出来,并提供默认实现(现提供3种实现)

4 添加参数, 可选择是否intercept Object对象中的方法(在上面3个方法中另加3个方法).


俺重写后,共8个类,4个关于dock优先级的strategy类加起来驶200行,4个核心类200行(不过俺没写注释)-_-
39 楼 ajoo 2006-12-14  
直接用getDeclaredMethods不好。这样继承就不能用了,只能用最下面的那个类里面的方法。

我改了一下,现在缺省直接delegate这三个hashCode(), equals(), toString()调用了(如果这个类没有定义这三个方法)。


equals()地实现相当麻烦,需要考虑unwrap dynamic proxy。对cglib尤其困难,我不知道怎么unwrap一个cglib enhanced的对象实例
38 楼 shaucle 2006-12-14  
还有这个,
final Class[] itfs = c.getInterfaces();
for (int i = 0; i < itfs.length; i++) {
int itfDepth = 1 + getHierarchyDepth(itfs[i]);
//这里调用itfs[i].getSuperclass()==null
if (itfDepth > depth) {
depth = itfDepth;
}
}
37 楼 ajoo 2006-12-14  
getDeclaredMethods不好。by-design我就是要拦截equals(), hashCode(), toString()的。

用户如果想delegate很简单,就实现一下delegate就是了。(equals的delegate还要写点if instanceof代码的)

我就在我们的项目中自己实现了一个DelegateObject来负责delegate。
具体类继承一下就是了。
36 楼 shaucle 2006-12-14  
ajoo 写道
shaucle 写道
D d=(D)Implementor.proxy(D.class, new Object());
如果D中实现了如hashCode之类的方法,那你的with(也就是那个new Object())会intercept D的hashCode么? (cls.getMethods())
不知道你的CglibUtils怎么实现的?
我这边测的会.

会的。
cglib没有大区别,就是允许asType是一个有default constructor的non-final类



getMethods -> getDeclaredMethods??就行了
35 楼 ajoo 2006-12-13  
shaucle 写道
final Class[] itfs = c.getInterfaces();
        for (int i = 0; i < itfs.length; i++) {
            int itfDepth = 1 + getHierarchyDepth(itfs[i]);
//这里调用itfs[i].getSuperclass()==null
            if (itfDepth > depth) {
                depth = itfDepth;
            }
        }

另外,如果
对于:f(A a, B b)
有如下intercept方法:
f(A2 a, B1 b)//A2中的2代表有2层继承
f(A1 a, B2 b)
那应该intercept哪一个?


没有试图对这个给出定义。估计实际上是第一个f。使用者应该避免这种情况发生。
34 楼 ajoo 2006-12-13  
shaucle 写道
D d=(D)Implementor.proxy(D.class, new Object());
如果D中实现了如hashCode之类的方法,那你的with(也就是那个new Object())会intercept D的hashCode么? (cls.getMethods())
不知道你的CglibUtils怎么实现的?
我这边测的会.

会的。
cglib没有大区别,就是允许asType是一个有default constructor的non-final类
33 楼 shaucle 2006-12-13  
final Class[] itfs = c.getInterfaces();
        for (int i = 0; i < itfs.length; i++) {
            int itfDepth = 1 + getHierarchyDepth(itfs[i]);
//这里调用itfs[i].getSuperclass()==null
            if (itfDepth > depth) {
                depth = itfDepth;
            }
        }

另外,如果
对于:f(A a, B b)
有如下intercept方法:
f(A2 a, B1 b)//A2中的2代表有2层继承
f(A1 a, B2 b)
那应该intercept哪一个?

32 楼 shaucle 2006-12-13  
getMethods -> getDeclaredMethods??

相关推荐

    酒窝状换热板强化换热效果分析

    设计了一种酒窝状换热板,利用Fluent软件对酒窝板、平板及波纹板的换热及压降特性进行了模拟,对这3种板在不同流速下板间流道内壁面平均换热系数、换热量、平均努塞尔数以及摩擦阻力的变化特性进行了对比分析。...

    《小酒窝》教学设计.doc

    《小酒窝》教学设计是针对音乐教育领域的一份详细教案,旨在教授小学生学习和表演歌曲《小酒窝》,同时欣赏并理解乐曲《我们多么幸福》。教学目标旨在通过多样的教学方法,培养学生的音乐感知力、创造力以及对音乐...

    人音三年级上册小酒窝PPT教案学习.pptx

    人音三年级上册小酒窝PPT教案学习.pptx

    小酒窝三年级上册人音小学音乐学唱PPT学习教案.pptx

    这篇PPT是一个针对小学三年级学生的音乐学唱课程,主要教授歌曲《小酒窝》。《小酒窝》是一首充满快乐和甜美的歌曲,适合孩子们学习,以培养他们对音乐的兴趣和基本的音乐素养。 首先,课程介绍了歌曲的速度和情绪...

    人音版三年级上册小酒窝PPT教案学习.pptx

    人音版三年级上册小酒窝PPT教案学习.pptx

    三年级上册音乐教案 第一单元《小酒窝》人音版(五线谱)(2014秋).doc

    这篇文档是关于三年级上册音乐课程的一个教案,教学内容为《小酒窝》这首歌,采用的是人音版教材,以五线谱的形式呈现。教学目标是让学生能够学唱这首歌曲,体验并表达出歌曲中甜美、活泼的情绪,同时激发他们对童年...

    酒窝窝DIGG类web2.0全站 -ASP源码.zip

    【标题】"酒窝窝DIGG类web2.0全站 -ASP源码.zip" 提供的是一款基于ASP编程语言的Web2.0网站源码,适用于构建互动性强、用户参与度高的社交平台。Web2.0是互联网发展的一个重要阶段,强调用户的交互性、共创性和分享...

    酒窝143

    【酒窝143】项目概述 "酒窝143"这个名称可能是指一个项目的代号或主题,但它本身并没有直接提供关于IT技术的知识点。不过,从提供的压缩包文件名“dimple143-master”来看,我们可以推测这可能是一个开源软件项目...

    四川省仁寿县城北实验初级中学2020学年八年级生物下学期第一次月考试题(无答案) 新人教版.doc

    15. 酒窝性状遗传分析:儿子、儿媳均有酒窝但生出无酒窝孩子,说明他们都是杂合子(Aa),再生一个孩子有酒窝的概率为75%,无酒窝的概率为25%。 以上知识点涵盖了生物学的多个核心概念,如生物生殖、发育、遗传规律...

    rcdimple:htmlwidgets的rCharts +酒窝

    rcdimple | htmlwidget rcdimple是在凹坑片的版本 。 我们的目标是直接从R漂亮,可定制的d3.js图表,并且只需最少的代码并且不了解JavaScript。 首先,可以使用devtools::install_github进行安装。...

    四川省仁寿县城北实验2014 2015学年八年级生物下学期第一次月考试题(无答案) 新人教版.doc

    - 若有酒窝为显性,无酒窝为隐性,有酒窝的祖父母、儿子、儿媳可能基因型为Aa,孙子无酒窝则基因型为aa。 - 儿子、儿媳再次生育,有酒窝孩子的概率为50%,因为他们都是Aa,子代可能为AA或Aa,其中Aa表现为有酒窝。...

    六年级语文总复习之句型转换教学设计1电子版教(学)案.doc

    - 扩句与缩句:扩句是在简单句的基础上增加修饰词,使其更具体,如"脸蛋印着酒窝"变为"可爱的脸蛋印着迷人的酒窝";缩句则是去除修饰成分,保留句子核心,如"脸蛋印着酒窝"可以简化为"脸蛋印着酒窝"。 3. **反问...

    生物历年大题归纳遗传题.doc

    - 小明的家庭中,如果有酒窝是显性(A),无酒窝是隐性(a),小明父亲无酒窝,因此其基因型为aa,母亲有酒窝,基因型为AA或Aa。反之,如果无酒窝是显性,有酒窝是隐性,则母亲的基因型为aa,父亲必须是Aa,因为...

    winbeep for python

    使用python给你beep个"祝你生日快乐" 和 "小酒窝" 简介不够代码来凑 import winsound def winbeep_di(): winsound.Beep(1000, 100) ....此处省略500宇宙代码 if __name__ == '__main__': winbeep_di() ...

    我自画像作文怎么写

    描述时,可以用比喻、拟人等修辞手法增加语言的表现力,如“笑起来非常好看,像是小酒窝里面装了酒一样”。外貌描述不仅要细致,还要力求生动、有趣,让人印象深刻。 其次,性格特征的呈现是自画像作文的重点。性格...

    贵州省六盘水市第十三中学八年级生物下册 第七单元 第二章 第三节 基因的显性和隐性导学案(无答案) 新人教版

    此外,一对无酒窝的夫妇无法生育出有酒窝的子女,因为有酒窝的基因D是显性的,而决定无酒窝的基因d是隐性的,所以无酒窝的夫妇基因型只能是dd,无法提供D基因给子女。 在能力提升环节,卷舌与非卷舌的例子进一步...

    小学六年级语文总复习之句型转换教学教案教(学)案.doc

    例如,"脸蛋印着酒窝"可以扩写为"可爱的脸蛋印着迷人的酒窝",缩写为"脸蛋印着酒窝"。 - **反问句与陈述句的互换**:反问句常用来强调陈述,转换时要去掉反问词,调整语气,如"我们是小学生,难道不要好好学习吗?...

    夸奖一个女孩子的话.doc

    3. 你笑起来的样子最为动人,两片薄薄的嘴唇在笑,长长的眼睛在笑,腮上两个陷得很举动的酒窝也在笑。 4. 青翠的柳丝,怎能比及你的秀发;碧绿涟漪,怎能比及你的眸子; 5. 你热情似火,你的微笑让我神魂颠倒 这些...

    自我介绍的作文精选.doc

    例如:“我是一个阳光的女孩,虽然谈不上特别美丽,但也不丑陋,上翘的嘴角和薄薄的嘴唇,笑起来还有浅浅的酒窝。” 3. **性格特点**:性格特征是自我介绍中的重要组成部分,能反映你的内在世界。如:“我性格热情...

    同学的道歉信集锦五篇.docx

    例如:“每当想起我们在一起同窗时的纯真岁月,你从十岁多的小丫头始终到二十多年后的今日,总是漂美丽亮的,留着迷人的酒窝,未见过你扎辫子……,其情其景,恍如昨日!”这种描述不仅表达了写信人对美好时光的怀念...

Global site tag (gtag.js) - Google Analytics