TDD中的一些问题

1. 我需要去测试get/set方法吗?

这个问题一直是TDD中比较典型的一个问题。有两个观点,一个是不需要测试,因为get/set代码很简单,测试没有什么意义,除非是有特别的逻辑在里面。另一个观点是需要测,否则你的TDD就有缺陷。对于这个问题,我个人觉得需要这样看,第一,你提供get/set方法用途是什么,第二是你要怎么去测试它们。如果你的测试代码是这么写的:

@Test
public void testGetSetX() {
    setX(23);
    assertEquals(23, getX());
}
或者
@Test
public void testGetSetX() {
    x = 23;
    assertEquals(23, x);
}
或者
@Test
public void testGetSetX() {
    assertEquals(23, 23);
}

那么我觉得没有必要写这样的测试代码,因为这不是在测你自己的代码,而是在验证Java的编译器。但,如果是这样的代码

@Test
public void testCreate() {
    assertEquals(23, new MyClass(23).getX());
}

那么显然是有意义的,通常我们可以验证带参数的构造函数是否正确工作。 而对于set来说也是一样,

@Test
public void testPrintMessage() {
    MyClass mc = new MyClass();
    mc.setX(23);
    assertEquals("the x is 23", mc.printMessage());
}

这同时引出第二个问题

2. 什么才是真正意义上的TDD? TDD的T是test, D是driven, D是design. 这里test可以有多种解释: 单元测试, 业务逻辑测试,功能测试. 但我认为单元测试是比较符合含义的. 那么什么是单元测试? 很多人都不是真正的清楚. 就上面说的例子来看我可以为每一个函数添加测试, 那这样就是单元测试了吗? 不, 这不是单元测试. 这里指的单元是功能单元,而不是实现单元.一个类的每一个函数都可以称之为一个实现单元, 但一个实现单元并不一定是一个功能单元. 只有这个实现单元在业务逻辑上有单独的意义时,它才可称为功能单元(就上面的例子来说创建一个业务对象是一个功能单元), 也只有构建用于功能单元的测试才能称为单元测试. 之所以要以功能单元为最小测试单位是因为通常来说在软件开发过程中业务逻辑的变化频率要远少于实现逻辑的变化频率. 如果我们的测试构建于实现逻辑之上, 那么测试与实现是紧耦合的,我们就很难对实现进行重构或者优化(在项目的开发后期往往会陷入牵一发而动全身的情况). 而构建于功能单元之上的测试则不会有这样的缺陷.

3. 什么是Mock, Fake, Dummy? 在开发单元测试过程中,我们经常会听到Mock, Fake, Dummy的字样. 不过我想很少人会去注意它们之间的区别. 从字面意义上讲都是"假的"意思, 那么区别是什么? 首先是Mock, mock的含义是替换实现, 并加以验证. mock的通常的做法是构建一个伪接口来代替真实接口, 当程序调用到该接口时返回一个预置的对象(可以是真对象也可以是假对象). 最关键是我们要去验证该接口是否真的被调用. 所以我们通常可以看到一个verify操作在单元测试最后. Fake的含义是伪对象,就是构建一个假的对象来替换真实对象, Fake更倾向于数据实体. Dummy的含义是哑对象. 哑对象就是无意义的对象, 诸如null或是new object(对业务无价值的对象). 只起到一个占位的作用,而没有什么具体含义. 这里有篇文章很全面的阐释相关的内容

总结一下,tdd是一个agile实践里面很重要的一个实践. 充分理解tdd的含义和目的将有助于更好的执行agile过程.

posted @ 2012-01-08 11:56  moonz-wu  阅读(542)  评论(0编辑  收藏  举报