PHP测试驱动开发介绍

发表于:2012-03-14来源:译言网作者:子非鱼.点击数: 标签:PHP;测试驱动开发
开发PHP产品有很多不同的方法。我们大多数倾向于从一个简单的脚本开始,逐步向前推进。 或许我们可以预先列出我们的脚本,但是我们往往是停留在开发阶段,在需要测试的时候不会真正的去开始测试。基本上,我们是先开发后测试。

  摘要

  本文向你介绍测试驱动开发的概念,并用一个简单的示例项目来做示范。

  介绍

  开发PHP产品有很多不同的方法。我们大多数倾向于从一个简单的脚本开始,逐步向前推进。 或许我们可以预先列出我们的脚本,但是我们往往是停留在开发阶段,在需要测试的时候不会真正的去开始测试。基本上,我们是先开发后测试。

  但是这样做或许不是最好的办法,可能会在今后带来问题。这就是为什么一些开发者提倡一种不同的开发方式,叫做测试驱动开发(TDD)的原因- 就是先测试后开发。

  你可能会疑惑这样该怎么做,而这正是本文将讨论的。我将带领你们通过一个真实的简单项目去示范TDD如何工作。本文和示例项目都基于Noel Darlow(“McGruff”)在论坛中向另一个论坛成员演示TDD如何工作的讨论。

  我们的示例项目是一个Biter类,它通过使用正则表达式可以“咬掉”字符串中的片段,就象这样:

  bite ('/pattern/');?>

  我们的类也将修改原始的字符串,把匹配的部分去除(所以我们叫它“吞噬者”)。

  让我们从设置测试框架开始。

  设置测试框架

  由于我们从测试出发,我们需要有一些测试框架。我将使用SimpleTest 框架,仅仅因为我最熟悉它。

  下载一份SimpleTest的拷贝,把它安装在你本机或者你的服务器上。然后创建一个叫做"test_biter.php"的新文件,里面写下面的代码:

  require_once 'simpletest/unit_tester.php';

  require_once 'simpletest/reporter.php';

  class BiterTestCase extends UnitTestCase {

  function testSetup () {

  $this->assertTrue(false);

  }

  }

  $test = new BiterTestCase('TDD Biter Test');

  $test->run(new HtmlReporter());

  ?>

  让我们分析一下这个例子。首先我们包含了一些SimpleTest框架的文件(你要确认一下路径是否和你的一样)。接着我们建立了一个叫做BiterTestCase的新类,它将用来测试我们的Biter类。象你看到的一样,BiterTestClase类继承于UnitTestCase类,这个意味着BiterTestClass是我们第一个真正意义上的测试用例

  BiterTestClass类只有一个方法调用叫做'testSetup'。任何以“test”开头的方法都会被SimpleTest框架自动执行,因此它们应该是被用来测试项目中的某个部分。在上面的例子中,我们通过调用assertTrue()方法来确认框架被正确设置。

  例子中的后面两行是建立一个测试用例的实例,然后运行所有测试。如果所有设置都正确的话,你会得到下面的输出:

setup_thumb.jpg

  现在我们已经设置好了测试框架并正常运行。让我们开始我们的Biter类。

  第一个测试

  在我们测试Biter类的任何功能之前,我们必须确认这个类存在。我们当然也是写一个测试来做这件事:

  require_once 'simpletest/unit_tester.php';

  require_once 'simpletest/reporter.php';

  class BiterTestCase extends UnitTestCase {

  function testClassExists() {

  $this->assertTrue(class_exists('Biter'), 'Biter class exists');

  }

  }

  $test = new BiterTestCase('TDD Biter Test');

  $test->run(new HtmlReporter());

  ?>

  现在运行上面的测试。不要创建类或者包含其他内容;先运行测试。由于'Biter' 类不存在,你会看到下面的输出:

class_exists_fail_thumb.jpg

  如你所见,我们的测试指出'Biter'类不存在。在TDD中,你总是从一个失败的测试开始工作。

  现在我们必须让测试能够通过,做到这点需要创建Biter类。建立一个叫'biter.php'的新文件,写入如下代码:

  Class Biter {

  }

  ?>

  然后把Biter类包含到我们的测试文件,加入如下行:

  require_once 'biter.php';

  现在再运行测试。这次它们会通过了,输出如下:

class_exists_su<STRONG><A href=ccess_thumb.jpg" border="1" height="30" src="http://www.phpit.net/demo/introduction%20tdd%20php/class_exists_success_thumb.jpg" width="215" />

  在创建Biter类的时候,我们走出了TDD的第一步。首先我们创建测试,然后再做实际的开发。

  在目前我们的Biter类还没有任何功能,下面让我们开始我们的Biter类的第一部分:“开始吞噬”。

  Biter返回正确的匹配吗?

  我们希望第一步明确的是当我们调用bite()方法的时候Biter类将返回正确的匹配,因此,让我们就此写一个测试:

  function testBiteReturnsAPatternMatch() {

  $biter =& new Biter;

  $haystack = 'foobar';

  $this->assertEqual(

  $biter->bite('/foo/', $haystack),

  'foo',

  'Biter returns correct match');

  }

  这个测试确认biter返回正确的匹配。它使用了assertEqual()方法,从名字我们就能知道这个方法的意思。把测试增加到我们的测试集,然后再运行测试。它会出错甚至返回一个致命错误,因为我们还没提供bite()方法。你会看到下面的输出:

原文转自:http://www.ltesting.net