TDD(测试驱动开发)

《Effective Unit Testing》 读书笔记 6

2018-03-05  本文已影响46人  李冬的读书笔记

本书第二部分中主要介绍了可读性/可维护性/可靠性三个方面的code smell或者说反模式(anti-pattern)。
我们首先看可读性的code smell. 再次解释一下所谓可读性,就是代码的意图和行为能通过阅读代码就能得到准确而清晰的表达。

@Test
public void outputHasLineNumbers() {
    String content = "1st match on #1\nand\n2nd match on #3";
    String out = grep.grep("match", "test.txt", content);
    assertTrue(out.indexOf("test.txt:1 1st match") != -1);
    assertTrue(out.indexOf("test.txt:3 2nd match") != -1);
}

其中的indexOf 和 magic number -1 都过于和java的String类的实现相关了。
修改后的版本用到了org.junit.JUnitMatchers#containsString()方法,对比之前,是不是可读性好了很多呢?

@Test
public void outputHasLineNumbers() {
    String content = "1st match on #1\nand\n2nd match on #3";
    String out = grep.grep("match", "test.txt", content);
    assertThat(out, containsString("test.txt:1 1st match"));
    assertThat(out, containsString("test.txt:3 2nd match"));
}

我们应该追求测试代码的本质,也就是正确的行为,而不是去测试代码的实现细节。

public class PlatformTest {
  @Test
  public void platformBitLength() {
    assertTrue(Platform.IS_32_BIT ^ Platform.IS_64_BIT);
  }
}

应该改成下面这样

public class PlatformTest {
 @Test
  public void platformBitLength() {
   assertTrue("Not 32 or 64-bit platform?",
     Platform.IS_32_BIT || Platform.IS_64_BIT);
   assertFalse("Can’t be 32 and 64-bit at the same time.",
     Platform.IS_32_BIT && Platform.IS_64_BIT);
 }
}
public class TestRuby {
  private Ruby runtime;
  @Before
  public void setUp() throws Exception {
    runtime = Ruby.newInstance();
  }
  @Test
  public void testVarAndMet() throws Exception {
    runtime.getLoadService().init(new ArrayList());
    eval("load 'test/testVariableAndMethod.rb'");
    assertEquals("Hello World", eval("puts($a)"));
    assertEquals("dlroW olleH", eval("puts $b"));
    assertEquals("Hello World",
    eval("puts $d.reverse, $c, $e.reverse"));
    assertEquals("135 20 3",
    eval("puts $f, \" \", $g, \" \", $h"));
  }
}

上面这段代码的最大问题就在于 eval("load 'test/testVariableAndMethod.rb'"); 这句话。这个测试从外部加载了另一个ruby文件,读者不两个文件对比着看,根本不知道在测试什么。
解决办法是,如果testVariableAndMethod.rb这个文件内容不多的话,直接把文件内容插在测试代码里(inline)。如果一定要分开放的话,要和测试放在同一个目录下面,要能通过相对路径来访问。

  public class BowlingGameTest {
  @Test
  public void perfectGame() throws Exception {
    roll(pins(10), times(12));
    assertThat(game.score(), is(equalTo(300)));
  }
  private int pins(int n) { return n; }
  private int times(int n) { return n; }
}
@Test
public void count() {
  Data data = project.getData();
  assertNotNull(data);
  assertEquals(4, data.count());
}

上面代码中的第一个null断言不需要写,因为这并不是这个测试方法所要测试的逻辑。虽然说隐式的假设data不为空不是完全正确,但是显式去判断这种无关紧要的东西会影响可读性。另外就算不写这句话,如果data为null了测试同样会抛错导致测试失败,所以也不会影响测试结果。

可读性的code smell到此介绍结束,下一章将介绍可维护性。

上一篇 下一篇

猜你喜欢

热点阅读