锁定老帖子 主题:我的酒窝
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2007-01-04
alin_ass 写道 用你这个取代mock类,万一接口方法名变了,重构挺麻烦的
我不是说:一般情况下你应该用implements关键字吗?只对“第三方接口”使用,如Connection, Map之类的。这些东西的签名不会变的,所以没有方法名变更带来的问题,而dimple可以帮你避免使用"implements"关键字创建stub带来的当接口在新版本里面增加新的方法的时候造成的问题。 还有,jmock也有重构问题的 |
|
返回顶楼 | |
发表时间:2007-01-05
看了一下发型包,已经0.4啦?现在有sample了么?有没有想好写一些什么经典应用场景呢?比如在做stub的情况下,和easymock做一个对比。至少可以告诉大家,在只要stub的情况下,犯不着搬出mock框架这么重的东西来。
|
|
返回顶楼 | |
发表时间:2007-01-05
ajoo 写道 再举一个adapter的例子。
不知道大家遇到过这样的情况没有。有一个api,有这个接口签名: runApi(Map map){ ... map.get(...); ... } 它仅仅使用get()一个方法,但是因为种种原因,并没有使用最小接口(我认为这种设计是非常正常的),而是用了这个java.util.Map接口。 在使用这个api的时候,我们不幸的没有一个Map对象,而只有一个proprietary的PropertyMap(或者HttpServletRequest也行)对象: interface PropertyMap { String getProperty(String key); boolean containsKey(String key); Set keySet(); } 需要写个adapter吧?目标代码如下: PropertyMap pmap = ...; runApi(convertToMap(pmap)); 那么这个convertToMap怎么写呢? Map接口相当的肥厚阿。继承AbstractMap的话要实现entrySet(),我们也没有。而我们明明知道runApi()只需要一个能支持get()的Map就成了。 一个方法呢,就是用dimple,下面是一个pojo的adapter(不依赖dimple): public class PropertyMapAdapter { private final PropertyMap pmap; public Object get(Object key) { if(key instanceof String) { return pmap.get((String)key); } else return null; } public boolean containsKey(Object key) { if(key instanceof String) { return pmap.containsKey((String)key); } else return false; } public Set keySet() { return pmap.keySet(); } public boolean isEmpty() { return keySet().isEmpty(); } public int size() { return keySet().size(); } } 只需要实现我们关心的方法(一个安全的方法,可以显然PropertyMapAdapter implements Map,这样就可以用eclipse的代码生成来选择性地实现这些我们关心的方法,不会有typo。),不用管其它的乱七八糟的。 然后使用dimple,实现convertToMap如下: Map convertToMap(PropertyMap pmap) { return Implementor.proxy(Map.class, new PropertyMapAdapter(pmap)); } 搞定。 可见,dimple并不是仅仅可以用做aop的interceptor,它还是一个克服静态类型局限的OO利器亚。而且不象aspectj,相当的light-weight,没有什么侵入性。 它仅仅使用get()一个方法,但是因为种种原因,并没有使用最小接口(我认为这种设计是非常正常的),而是用了这个java.util.Map接口。 看了这个例子,我的看法: 如果在视线中 需要这么复杂的代码来做测试,那么就意味着个这个接口设计并不“正常”了,根据你提到的“仅仅用到了map.get()"的这个意思,那么接口应该这样设计: map.get()--->Object o runApi(Map map)--->runApi(Object o) { // not dependent on map} 这个例子我存在异议。 看着有点困惑。 如果对于 因为”stub“比较难写,需要一个工具框架来自动实现这么一个stub,我赞成。 但是如果 因为”测试“难写而拼命的使用这么一个框架,我觉得有点舍本求末了。 或许,回过头来重构设计和代码,让测试更容易写 ,或许这样获得事倍功半的效果呢? |
|
返回顶楼 | |
发表时间:2007-01-05
呵呵,有些系统提供的接口我们是重构不了的啊。所以实现这些接口就是价值所在了。
|
|
返回顶楼 | |
发表时间:2007-01-05
引用 这个例子我存在异议。 看着有点困惑。
如果对于 因为”stub“比较难写,需要一个工具框架来自动实现这么一个stub,我赞成。 但是如果 因为”测试“难写而拼命的使用这么一个框架,我觉得有点舍本求末了。 或许,回过头来重构设计和代码,让测试更容易写 ,或许这样获得事倍功半的效果呢? 这个例子不是测试阿。它的前提是: 一个模块设计成可以注射java.util.Map。这个设计是很自然的。 其他的普通客户代码都是直接用HashMap或者java.util.Properties之类的东西来注射。 单元测试代码也是用HashMap的。也没问题。 问题在于某个和第三方库或者legacy system集成的部分碰巧没有Map,而只有一个PropertyMap,这时就可以用dimple。 |
|
返回顶楼 | |
发表时间:2007-01-05
taowen 写道 看了一下发型包,已经0.4啦?现在有sample了么?有没有想好写一些什么经典应用场景呢?比如在做stub的情况下,和easymock做一个对比。至少可以告诉大家,在只要stub的情况下,犯不着搬出mock框架这么重的东西来。
easymock倒也不算多重。而且它还有重构安全的特性。 区别仅仅在于stub vs. mock。如果需要做interaction-based test,当然是easymock,没得说。而如果要做state-based test,用easymock来做stub就有点别扭。 我的sample都很简单,已经写在confluence里了。当然也许有点生造出来的嫌疑。你有什么好的例子么? |
|
返回顶楼 | |
发表时间:2007-01-05
taowen 写道 呵呵,有些系统提供的接口我们是重构不了的啊。所以实现这些接口就是价值所在了。
我所能想到的 ”需要实现这些接口/抽象类的“ 充要条件: 1) Easymock模拟的代码很难写 ,或者代码比用Dimple作stub要多得多 2)人家提供的接口是一个类,而不是一个接口。 对于1)如果我们依赖人家接口的一两个method,我觉的EasyMock写起来难度不大。 如果我们的逻辑依赖人家接口的大部分API 。 确实,stub要来得好得多。 但是此时,我可能就需要在 自己写一个stubImpl和用Dimple实现一个Stub来权衡了,但是这个结果是在 ”我们的逻辑需要依赖很多人家接口的method“情况下发生的,这样一来,估计看看Dimple的代码,满篇也是实现的代码了吧,在这个前提下,优势我暂时看不出来。 对于2) ,因为不用接口带来如此的难题,stub似乎不得不提出来了。但是作为选择,也可以用一个Adapter接口来封装人家的类。对这个Adapter接口的处理又回到了1) |
|
返回顶楼 | |
发表时间:2007-01-05
ajoo 写道 引用 这个例子我存在异议。 看着有点困惑。
如果对于 因为”stub“比较难写,需要一个工具框架来自动实现这么一个stub,我赞成。 但是如果 因为”测试“难写而拼命的使用这么一个框架,我觉得有点舍本求末了。 或许,回过头来重构设计和代码,让测试更容易写 ,或许这样获得事倍功半的效果呢? 这个例子不是测试阿。它的前提是: 一个模块设计成可以注射java.util.Map。这个设计是很自然的。 其他的普通客户代码都是直接用HashMap或者java.util.Properties之类的东西来注射。 单元测试代码也是用HashMap的。也没问题。 问题在于某个和第三方库或者legacy system集成的部分碰巧没有Map,而只有一个PropertyMap,这时就可以用dimple。 如果是这样的话,那么ConvertToMap 的逻辑也是有必要冒烟测试到的。 所以, 那测试也就很自然的从PropertyMap准备测试数据进行测试了,这样的测试也没有必要用DImple来模拟 ConvertToMap的逻辑阿,我只需要在测试里面测试到就可以了。 |
|
返回顶楼 | |
发表时间:2007-01-05
没有看到我说的“不是测试的问题”么?
这里面dimple是用在production代码里面的。测试代码不用dimple。 |
|
返回顶楼 | |
发表时间:2007-01-05
ajoo 写道 没有看到我说的“不是测试的问题”么?
这里面dimple是用在production代码里面的。测试代码不用dimple。 哦,不好意思,我满脑子都是测试,哈哈。 打错靶子了。 不过,我仍然想多啰嗦几句。 问题在于某个和第三方库或者legacy system集成的部分碰巧没有Map,而只有一个PropertyMap,这时就可以用dimple。 这个例子用Dimple确实可以,但是我看不出我直接用一个Utils.convertToMap的逻辑有何优势。 另外,对于你提到的需要拦截Connection.close ,而需要一个ConnectionAdapter 来统一拦截,以此提出了Dimple的设计。 我对这个出发点也提出疑义。 虽然这是一个很好的办法,但是我更倾向于用一个统一的接口来open,close Connection来达到统一拦截的目的,或许这个接口语义很弱,但是在一个项目/框架开发里面,把这个需求提到每个开发者的需求也不是很难的事情。 虽然,这里有点类似AOP的概念,但是对于AOP,正如ROD所说的,AOP不应该和OOP成为对立的关系,两者应该是互补的关系。 AOP应该在OOP设计良好的基础上成为良好的补充。 |
|
返回顶楼 | |