phpUnit初学者

时间:2010-12-04 15:48:42

标签: php testing phpunit

我如何开始使用phpUnit作为我已经完成的一系列函数和类的测试框架?


编辑:是的,我已经阅读了文档。基本上我在遵循BankAccount示例时尝试过测试。 但我得到错误:

Warning: require_once(PHP/CodeCoverage/Filter.php) [function.require-once]: failed to open stream: No such file or directory in [...]/unitTest/phpunit.php on line 38

此外,php脚本似乎以#!/usr/bin/env php开头,表明它们应该从控制台运行。我宁愿从浏览器运行这些......

假设我有一个返回字符串的函数f1()。应该如何进行测试?我错过了什么吗?

2 个答案:

答案 0 :(得分:10)

  

对测试框架的简短介绍

PHPUnit提供了一个简单的框架,用于创建测试套件以自动测试函数和类。 PHPUnit的灵感来自JUnit,它由Kent Beck和Erich Gamma创建,作为极限编程的工具。 XP的一个规则是尽可能经常地尽早测试小型软件组件,这样您就不必在设置和测试依赖于类的大型应用程序时修复API中的错误和错误。虽然单元测试是XP中的基本规则之一,但您不必切换到XP以从PHPUnit中受益。 PHPUnit是一个测试类或一组函数的好工具,可以简化开发周期并帮助您避免无休止的调试会话。

  

工作程序

通常,您会编写一个类,使用echo()var_dump()进行一些非系统测试。在此之后,您在应用程序中使用该类,并希望一切正常。要从PHPUnit中受益,您应该重新考虑这个流程。最好的方法是:

  1. 设计您的课程/ API
  2. 创建测试套件
  3. 实现类/ API
  4. 运行测试套件
  5. 修复失败或错误并再次转到#4
  6. 看起来这可能需要很多时间,但这种印象是错误的。使用PHPUnit创建测试套件只需几分钟,并且只运行测试套件几秒钟。

      

    设计一个类

    让我们从一个小例子开始:一个字符串类。首先,我们创建一组函数声明来处理字符串:

    ---- string.php ----
    
    <?php
    class String
    {
        //contains the internal data
        var $data;
    
        // constructor
        function String($data) {
            $this->data = $data;
        }
    
        // creates a deep copy of the string object
        function copy() {
        }
    
        // adds another string object to this class
        function add($string) {
        }
    
        // returns the formated string
        function toString($format) {
        }
    }
    ?>
    
      

    创建测试套件

    现在我们可以创建一个测试套件,它可以检查字符串类的每个函数。测试套件是从PHPUnit_TestCase继承的普通PHP类,包含测试函数,由函数名中的前导'test'标识。在测试函数中,必须将期望值与要测试的函数的结果进行比较。此比较的结果必须委托给assert*()-family的函数,该函数决定函数是否通过测试。

    ---- testcase.php ----
    
    <?php
    
    require_once 'string.php';
    require_once 'PHPUnit.php';
    
    class StringTest extends PHPUnit_TestCase
    {
        // contains the object handle of the string class
        var $abc;
    
        // constructor of the test suite
        function StringTest($name) {
           $this->PHPUnit_TestCase($name);
        }
    
        // called before the test functions will be executed
        // this function is defined in PHPUnit_TestCase and overwritten
        // here
        function setUp() {
            // create a new instance of String with the
            // string 'abc'
            $this->abc = new String("abc");
        }
    
        // called after the test functions are executed
        // this function is defined in PHPUnit_TestCase and overwritten
        // here
        function tearDown() {
            // delete your instance
            unset($this->abc);
        }
    
        // test the toString function
        function testToString() {
            $result = $this->abc->toString('contains %s');
            $expected = 'contains abc';
            $this->assertTrue($result == $expected);
        }
    
        // test the copy function
        function testCopy() {
          $abc2 = $this->abc->copy();
          $this->assertEquals($abc2, $this->abc);
        }
    
        // test the add function
        function testAdd() {
            $abc2 = new String('123');
            $this->abc->add($abc2);
            $result = $this->abc->toString("%s");
            $expected = "abc123";
            $this->assertTrue($result == $expected);
        }
      }
    ?>
    
      

    第一次试运行

    现在,我们可以进行第一次测试。确保所有路径都正确,然后执行此PHP程序。

    ---- stringtest.php ----
    
    <?php
    
    require_once 'testcase.php';
    require_once 'PHPUnit.php';
    
    $suite  = new PHPUnit_TestSuite("StringTest");
    $result = PHPUnit::run($suite);
    
    echo $result -> toString();
    ?>
    

    如果从命令行调用此脚本,您将获得以下输出:

    TestCase stringtest->testtostring() failed: expected true, actual false
    TestCase stringtest->testcopy() failed: expected , actual Object
    TestCase stringtest->testadd() failed: expected true, actual false
    

    每个函数都没有通过测试,因为你的字符串函数没有返回我们定义为期望值的函数。

    如果您想通过浏览器调用脚本,则必须将脚本放在正确的html页面中并调用$result->toHTML()而不是$result->toString()

      

    实施

    好的,让我们从我们的字符串类的实现开始。

    ---- string.php ----
    
    <?php
    class String
    {
        //contains the internal data
        var $data;
    
        // constructor
        function String($data) {
            $this->data = $data;
        }
    
        // creates a deep copy of the string object
        function copy() {
            $ret = new String($this->data);
            return $ret;
        }
    
        // adds another string object to this class
        function add($string) {
            $this->data = $this->data.$string->toString("%ss");
        }
    
        // returns the formated string
        function toString($format) {
            $ret = sprintf($format, $this->data);
            return $ret;
        }
    }
    ?>
    

    实施完成后我们可以再次运行测试:

    ~>
    php -f stringtest.php
    
    TestCase stringtest->testtostring() passed
    TestCase stringtest->testcopy() passed
    TestCase stringtest->testadd() failed: expected true, actual false
    

    D'哦!最后一次测试失败了!我们犯了打字错误。将string.php中的第16行更改为

    <?php
    $this->data = $this->data.$string->toString("%s");
    ?> 
    

    再次运行测试:

    ~>
    php -f stringtest.php
    
    TestCase stringtest->testtostring() passed
    TestCase stringtest->testcopy() passed
    TestCase stringtest->testadd() passed
    

    现在一切都好!

      

    结论

    测试三个简单函数似乎有很多工作要做吗?不要忘记,这是一个小例子。考虑更大,更复杂的API,如商店应用程序中的数据库抽象或篮子类。 PHPUnit是一个很好的工具,用于检测类实现中的错误。

    通常,您需要重新实现或重构在多个不同应用程序中使用的大类。没有测试套件,你在其中一个依赖于你的类的应用程序中破坏某些东西的可能性非常高。感谢单元测试,您可以为您的类创建一个测试套件,然后重新实现您的类,并确保只要新类通过测试,依赖于类的应用程序就可以工作。

    二手来源:http://pear.php.net

答案 1 :(得分:0)

如果可能,我真的建议从命令行运行PHPUnit。在我们公司,这是不可能的,但我们正在努力,这使我们的测试不稳定......

我假设您必须使用set_include_path()为php设置一些包含路径,因此phpunit会找到其余文件。但这可能还不够......

我们的代码看起来像这样

// you will have to write your own class here that collects the tests
$collector = new Unit_Test_Collector();
$suite = $collector->getSuite();

//$config is an array of phpunit config options

PHPUnit_TextUI_TestRunner::run($suite, $config);