浏览 11727 次
锁定老帖子 主题:俺摸,俺摸,俺默默摸
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2008-01-16
一只猪:“可不是!到哪儿都被采访,这名猪也有隐私权滴!最近特想过普通猪的生活。这不,洗尽铅华,老老实实地躲圈里整Java呢” 话说这Java的一级摸客(EasyMock),老猪最近用的满多的。在Java 4里面不忍卒睹的代码在java 5里面骤然变得性感许多。不过用的多了,也发现有些不方便的地方。最不爽的就是:俺老猪不是粗心吗?有时候不小心就会忘了EasyMock.verify()或者IMocksControl#verify()。 这一忘了不打紧,有些bug就藏在那,测试也过了,但是bug也没找出来。 有很多淫说这还不容易?用IMocksControl,然后在tearDown()里写control.verify(),就没事了。(不好,被你发现老猪还在用回立牌JUnit 3.8) 嘿嘿,老猪针对这种左倾机会主义思潮做出了最坚决的斗争。 为啥?且听老猪我慢慢到来。在tearDown()里面写verify()有三个很致命的毛病: 1。 JUnit 3.8的tearDown()相当于try-finally里面的finally。也就是说,即使你的test出现了异常,它也会被执行。因此如果你的测试代码还没等到verify()的时候就因为某种原因歇菜了(比如,某个assertEquals()失败了),这个异常会被吞噬掉,你得到的将会是一个毫无意义的EasyMock的verify()异常。 2。tearDown()很有可能被子类重载滴。万一子类忘记了调用super.tearDown()怎么办?”子类不应该忘“?呵呵,要我说你还不如干脆就”不应该“忘记调用verify()呢。这不是前门驱虎,后门进狼么? 3。不能不分3*7=21就verify呀同志!咱假如说,俺老猪懒,为了跑到绿草如茵的山坡睡个暖洋洋的懒觉,写了一个啥也不干的testStone(),反正回头就说这山叫石头山,山上有个石头洞,洞里有俩和尚在讲故事...(说走嘴了),迷迷糊糊闭着眼睛哼着小曲点击了一下my precious testStone()。“啦啦啦啦啦,啦啦啦啦,天空出彩霞呀,.哦?.哦.bug出来啦呀 ”。啥?居妍说俺的testEmpty错了?俺老猪是无辜地呀。因为俺啥也没干啊!是猴哥。没错,肯定是这弼马温!说啥不能还没replay()呢就verify()?废话,我也没让你verify呀。这个故事告诉我们,不能没事就verify(),你至少得知道人家replay()了没有先。 老猪的解决办法是做一个PorkMockTest类,然后在TestCase#runTest()上做文章: public class PorkMockTest extends TestCase { private IMocksControl control = null; private boolean replayed = false; private boolean verified = false; @Override protected void runTest() throws Throwable { super.runTest(); if (replayed && !verified) { verify(); } } private IMocksControl control() { if (control == null) { control = EasyMock.createMockControl(); } } public <T> T mock(Class<T> type) { return control.createMock(type); } protected void replay() { control().replay(); replayed = true; } protected void verify() { verified = true; control().verify(); } } 这个代码还比较简陋,还不处理strict和nice mock。不过呢,基本上就剩照猫画虎了——当然,我没跟你说就copy&paste啊,你怎么也得refactor一下才好意思见人吧? 好了,现在只要你继承我这个PorkMockTest,你就可以一直往前走,不用往两边看了。你可以理直气壮地忘掉verify()——要求我们懒惰如猪的程序员记住计算机可以搞定的东西是犯罪呀,对人民赤果果地犯罪! 好,现在我可以这么写了: public class LionHeadTest extends PorkMockTest { public void testHuoHou() { LionHead head = mock(LionHead.class); head.bite(); replay(); cook(head); // 忘记吧,忘记吧。忘记是一种幸福。能忘记的人才能快乐地吃狮子头啊! } } 欢乐的时光总是过得快,又到时间说白白。不要走开,广告之后请继续收看俺摸(mock),俺摸,俺默默摸! 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-01-17
不错!幽默!
|
|
返回顶楼 | |
发表时间:2008-01-17
生动啊~~~喜欢那个
// 忘记吧,忘记吧。忘记是一种幸福。能忘记的人才能快乐地吃狮子头啊! 呵呵 |
|
返回顶楼 | |
发表时间:2008-01-17
忘记verify(),那如果写test的时候忘了assertXXX(...),那情形不是一样么。写Unit测试的第一步不是先写出测试失败的Unit Case么?
|
|
返回顶楼 | |
发表时间:2008-01-17
kongxx 写道 忘记verify(),那如果写test的时候忘了assertXXX(...),那情形不是一样么。写Unit测试的第一步不是先写出测试失败的Unit Case么?
一样么?不一样吧?用assert,你要不就没写assert,也就是说你的需求意图根本没有表现在代码中,要不就写了这么一行来表达这个需求。 verify不同啊。你的需求是那些写在replay()之前的expectation。你期望foo()被调用,就写一个foo()。但是即使你根据需求写了这么多期望,如果你忘了verify(),也还是没用功。 打个比方,你要是忘了上班,不发你工资天公地道。但是如果你确实上班了,但是公司还要求你每天都到内部网上写一个“是的,我今天的工作不是无偿的,请付给我工资”,那么这个“忘记”就比较讨厌了是不? 我承认TDD会减轻“忘记”的问题。但是,不绝对吧?对下面一个测试: int runFoo(Foo foo) { return 0; } void testFoo() { Foo foo = mock(Foo.class); expect(foo.run()).andReturn(1); replay(); assertEquals(1, runFoo(foo)); } 它也变红,因为assertEquals()不通过。把runFoo()改成return foo.run(),就绿了。什么机会让你能够意识到verify()忘了呢? |
|
返回顶楼 | |
发表时间:2008-01-18
EasyMockTemplate 如何?
|
|
返回顶楼 | |
发表时间:2008-01-18
hax 写道 EasyMockTemplate 如何?
不好,不好。一个replay()很清楚地标示了expectation。要是怕看不清楚,放几个空行和传说中的神秘分隔符也足够了。 匿名类的语法实在比较烦。不值当的。 |
|
返回顶楼 | |
发表时间:2008-01-20
那是框架应该解决的问题,jmock就自动verify了。
|
|
返回顶楼 | |
发表时间:2008-01-21
easymock2.0好像不支持对一个返回值为空的方法期望抛出一个异常,他的IExpectationSetters只有在返回值不为空的时候才能addThrow,这个有点很不爽!
|
|
返回顶楼 | |
发表时间:2008-01-21
kjhot 写道 easymock2.0好像不支持对一个返回值为空的方法期望抛出一个异常,他的IExpectationSetters只有在返回值不为空的时候才能addThrow,这个有点很不爽!
EasyMock.expectLastCall().andThrow()? |
|
返回顶楼 | |