论坛首页 综合技术论坛

什么是“测试驱动开发”

浏览 71492 次
该帖已经被评为精华帖
作者 正文
   发表时间:2006-04-25  
firebody 写道

虽然是有理,但是单纯从上面的代码来看,我有种过渡设计/分离的味道,因为从代码的简洁程度来说,把一个只有十多行代码的method抽出到一个专门的接口,然后再用一个实现类来作,最好才能体现TDD就是设计的好处,我对此持有疑惑。

重构啊重构,重构也是有条件的。

我是觉得,如果这个method不是被多次用到,代码不会经常替换,就没必要这么做。
重构是为了消除bad smell。不是为了重构而重构。
0 请登录后投票
   发表时间:2006-04-25  
charon 写道
firebody 写道
charon 写道
此时,要求Bean实现的equals方法中按照name判等

你这个更不通用了,在简单的bean还行,因为equals就可以搞定。
万一我得bean的状态比较复杂呢? 还需要实现一个对应的equals方法?

而且,为了测试需要写一个符合测试规则的equals方法,感觉也不好吧。


那个bean是自己构造出来的,想要是什么状态就可以设置什么状态。
其实,那个equals不是一个符合测试规则的equals方法,而是一个一般的equals方法。而且,对象状态的判等,必须是可观测状态的判等,而且必须和equals的语义是一致的。这个和测试不测试没关系
在这个例子中,Bean实际上是不需要equals方法的,因为默认的够用了。
如果在构造状态比较多的bean对象的时候,适当注意那些引用对象的使用,默认的也够用了。

这个例子比较简单了,一个简单的Bean,自然可以轻松利用equals进行对象的判等。但是 很多的对象状态往往很复杂,比如一棵树,集合,或者带有关联的对象等等。equals总归是不能覆盖这些状态的。

另外我的习惯是equals和hashcode一起写 ,我性认为他们两个语义应该是一致的,单独写一个equals不大习惯,或许这跟老和HashMap打交道有关系吧。 所以除非又明确的需求特定一个equals的是线,不然我不会为了测试而写上equals方法的。
0 请登录后投票
   发表时间:2006-04-25  
firebody 写道
charon 写道
firebody 写道
charon 写道
此时,要求Bean实现的equals方法中按照name判等

你这个更不通用了,在简单的bean还行,因为equals就可以搞定。
万一我得bean的状态比较复杂呢? 还需要实现一个对应的equals方法?

而且,为了测试需要写一个符合测试规则的equals方法,感觉也不好吧。


那个bean是自己构造出来的,想要是什么状态就可以设置什么状态。
其实,那个equals不是一个符合测试规则的equals方法,而是一个一般的equals方法。而且,对象状态的判等,必须是可观测状态的判等,而且必须和equals的语义是一致的。这个和测试不测试没关系
在这个例子中,Bean实际上是不需要equals方法的,因为默认的够用了。
如果在构造状态比较多的bean对象的时候,适当注意那些引用对象的使用,默认的也够用了。

这个例子比较简单了,一个简单的Bean,自然可以轻松利用equals进行对象的判等。但是 很多的对象状态往往很复杂,比如一棵树,集合,或者带有关联的对象等等。equals总归是不能覆盖这些状态的。

在这个简单的例子中,用默认的equals判等就已经很大的改善了可读性,如果是复杂的例子,假设这个Bean里面有多个引用对象,写一个equals(当然,里面引用对象的equals是由其该对象自己实现的)会给你的测试代码可读性带来质的飞跃(不然,用IArgumentMatcher的测试代码将没有办法看了)。

引用

另外我的习惯是equals和hashcode一起写 ,我性认为他们两个语义应该是一致的,单独写一个equals不大习惯,或许这跟老和HashMap打交道有关系吧。 所以除非又明确的需求特定一个equals的是线,不然我不会为了测试而写上equals方法的。

为了便于测试连更复杂的工作也作了,难道不肯做这么一点事情?要知道,代码是代码,测试代码也是代码,也是要讲可读性的。实际上,所有对于代码的原则,都可以适用到测试代码。只不过真正那么做的人太少了。
0 请登录后投票
   发表时间:2006-04-25  
charon 写道
firebody 写道
charon 写道
firebody 写道
charon 写道
此时,要求Bean实现的equals方法中按照name判等

你这个更不通用了,在简单的bean还行,因为equals就可以搞定。
万一我得bean的状态比较复杂呢? 还需要实现一个对应的equals方法?

而且,为了测试需要写一个符合测试规则的equals方法,感觉也不好吧。


那个bean是自己构造出来的,想要是什么状态就可以设置什么状态。
其实,那个equals不是一个符合测试规则的equals方法,而是一个一般的equals方法。而且,对象状态的判等,必须是可观测状态的判等,而且必须和equals的语义是一致的。这个和测试不测试没关系
在这个例子中,Bean实际上是不需要equals方法的,因为默认的够用了。
如果在构造状态比较多的bean对象的时候,适当注意那些引用对象的使用,默认的也够用了。

这个例子比较简单了,一个简单的Bean,自然可以轻松利用equals进行对象的判等。但是 很多的对象状态往往很复杂,比如一棵树,集合,或者带有关联的对象等等。equals总归是不能覆盖这些状态的。

在这个简单的例子中,用默认的equals判等就已经很大的改善了可读性,如果是复杂的例子,假设这个Bean里面有多个引用对象,写一个equals(当然,里面引用对象的equals是由其该对象自己实现的)会给你的测试代码可读性带来质的飞跃(不然,用IArgumentMatcher的测试代码将没有办法看了)。

引用

另外我的习惯是equals和hashcode一起写 ,我性认为他们两个语义应该是一致的,单独写一个equals不大习惯,或许这跟老和HashMap打交道有关系吧。 所以除非又明确的需求特定一个equals的是线,不然我不会为了测试而写上equals方法的。

为了便于测试连更复杂的工作也作了,难道不肯做这么一点事情?要知道,代码是代码,测试代码也是代码,也是要讲可读性的。实际上,所有对于代码的原则,都可以适用到测试代码。只不过真正那么做的人太少了。

不错,用Matcher会导致代码的可读性非常差。 很多时候,往往会因为这个改变设计。 针对那行代码,其实我看了第三编就已经忍受不了了。
0 请登录后投票
   发表时间:2006-04-25  
引用

不错,用Matcher会导致代码的可读性非常差。 很多时候,往往会因为这个改变设计。 针对那行代码,其实我看了第三编就已经忍受不了了。
但是,我认为对equals的覆写并不认为是你说的"小事情“,一旦覆写了就要保证其语义的正确性。equals作为对象基本语义之一,我个人习惯对此比较谨慎。
默认的往往都能够按照默认的行为工作,但是覆写的话意味着你需要对这个equals的语义和对象的状态作充分的考虑。


不是指小事情,而是相比于从私有代码中抽取出接口并搞定一个实现类而言,实现一个对象的equals方法,那是轻量多了.
最轻量的方法当然是前面提到过的protected化。
0 请登录后投票
   发表时间:2006-04-25  
charon 写道
引用

不错,用Matcher会导致代码的可读性非常差。 很多时候,往往会因为这个改变设计。 针对那行代码,其实我看了第三编就已经忍受不了了。
但是,我认为对equals的覆写并不认为是你说的"小事情“,一旦覆写了就要保证其语义的正确性。equals作为对象基本语义之一,我个人习惯对此比较谨慎。
默认的往往都能够按照默认的行为工作,但是覆写的话意味着你需要对这个equals的语义和对象的状态作充分的考虑。


不是指小事情,而是相比于从私有代码中抽取出接口并搞定一个实现类而言,实现一个对象的equals方法,那是轻量多了.
最轻量的方法当然是前面提到过的protected化。

我删掉了还来不及。赫赫。 本来已经不想就着equals这个问题再讨论下去了,这个问题讨论起来很容易发散 。 不过那些matcher的代码确确实实比较让人费解和难看。
至于我们要讨论什么呢? 回到正题吧。赫赫,我们的结论是什么?
0 请登录后投票
   发表时间:2006-04-26  
hehe,应该已经忘记原来在讨论什么了吧。
除非再回过头去顺着看一边。
或者,从标题来看,大概是在说每个人对测试驱动开发的理解?
我的理解是,现在大的场面上把问题域分解到功能也好,用例也好,或者用户故事也好,总之是到一个团队成员可以操控的粒度。然后,根据这些中的某一项确定测试列表(这个列表就是近期工作指南),一项项以测试优先的方式来搞定代码,其间会在这个测试列表上面添加新的东西(实际上是在做问题的分解,或者,也能算是设计)。
但是,用TDD去规范某个方法的内部设计,是我所反对的。这是我和你以及robbin的分歧所在。其实我现在的做法和gigix的观点倒是有点相近的,只不过更加保守一点,就是说可以在测试用例中体现依赖(这个是正常的,而且这种依赖本来也是被注射进去的,或者说是可观测的),但是,仅此而已。是一个半透明的黑盒,但是我还是嫌它太透明了。
还有一点,对接口的分离上,我也持比较保守的态度,hehe
0 请登录后投票
   发表时间:2006-04-26  
charon 写道
hehe,应该已经忘记原来在讨论什么了吧。
除非再回过头去顺着看一边。
或者,从标题来看,大概是在说每个人对测试驱动开发的理解?
我的理解是,现在大的场面上把问题域分解到功能也好,用例也好,或者用户故事也好,总之是到一个团队成员可以操控的粒度。然后,根据这些中的某一项确定测试列表(这个列表就是近期工作指南),一项项以测试优先的方式来搞定代码,其间会在这个测试列表上面添加新的东西(实际上是在做问题的分解,或者,也能算是设计)。
但是,用TDD去规范某个方法的内部设计,是我所反对的。这是我和你以及robbin的分歧所在。其实我现在的做法和gigix的观点倒是有点相近的,只不过更加保守一点,就是说可以在测试用例中体现依赖(这个是正常的,而且这种依赖本来也是被注射进去的,或者说是可观测的),但是,仅此而已。是一个半透明的黑盒,但是我还是嫌它太透明了。
还有一点,对接口的分离上,我也持比较保守的态度,hehe

其实你已经说到点上了。
就是小步骤的进行,随时更新todoList和添加新的测试。

我前面写的那个例子说明我还没有完全体会TDD的含义,昨晚我熬夜重新再看了一遍kent beck的TDD实践。
我知道我遗漏了重要的一点:就是小步骤的添加todoList,添加测试代码,然后小步骤的实现功能,再让测试通过的基础上再优化代码以及重构。

拿我前面的例子来说,至少应该在写代码之前把基本需求列出来,然后写出一个基本的todoList,针对基本需求写一个未通过的测试,如果要使得这个测试通过需要好几个步骤或者比较麻烦,应该把问题分解,再列到todoList上,再针对这些被分解的小任务进行小步骤的添加测试--》使测试通过--》优化代码,重返往复,最后把最终的那个复杂的任务干掉。

就那我前免得例子来说。如果那个doSomeInternalLogic逻辑复杂的话,应该把它列出来作为一个单独的任务放到todoList里面去,单独测试。
就像你说得,可以把它作为一个protected方法进行测试。测试通过后,继续进行原来的任务。

我想我要自己要做TDD了。从我现在的做的JPA实现做起吧。
0 请登录后投票
   发表时间:2006-04-26  
就我看来,写单元测试和写实现,都是设计的过程。
单元测试意味着,设计元素的契约部分。实现意味着,设计元素的结构部分。契约是结构必须满足的充分必要条件。
0 请登录后投票
   发表时间:2006-04-26  
从项目角度,TDD比文档驱动成本更高.
0 请登录后投票
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics