我应该如何开始使用 PHPUnit 作为我已经制作的一堆函数和类的测试框架?

发布于 2024-10-05 20:45:39 字数 361 浏览 0 评论 0原文

我已经阅读了文档。基本上我在遵循 BankAccount 示例时尝试了测试。 但我收到错误:

警告:require_once(PHP/CodeCoverage/Filter.php) [function.require-once]: 无法打开流:第 38 行的 [...]/unitTest/phpunit.php 中没有此类文件或目录

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

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

I've already read the documentation. Basically I've tried tests while following the BankAccount example.
But I get errors:

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

Also, the PHP scripts seems to start with #!/usr/bin/env php which indicate they should be run from the console. I'd rather run these from the browser...

Suppose I have a function f1() that returns a string. How should the tests be made? Am I missing something?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

守望孤独 2024-10-12 20:45:39

测试框架简短介绍

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

日常工作

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

  1. 设计你的类/API
  2. 创建一个测试套件
  3. 实现类/API
  4. 运行测试套件
  5. 修复失败或错误,然后再次转到#4

这似乎需要很多时间,但这印象是错误的。使用 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'oh!上次测试失败了!我们犯了一个打字错误。将 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

A short introduction to the test framework

PHPUnit provides a simple framework for creating a test suite to automate testing of functions and classes. PHPUnit is inspired by JUnit which was created by Kent Beck and Erich Gamma as a tool for eXtreme Programming. One of the rules of XP is to test small software components as often and early as possible, this way you will not have to fix bugs and errors in the API while setting up and testing larger applications which depend on the class. While unit testing is one of the fundimental rules in XP, you don't have to switch to XP to benefit from PHPUnit. PHPUnit stands alone as a good tool for testing classes or a set of functions and will ease your development cycle and help you to avoid endless debug sessions.

Work routine

Normally, you would write a class, do some unsystematic tests using echo() or var_dump(). After this, you use the class in your application and hope everything is ok. To benefit from PHPUnit you should rethink the flow. The best way is to do this:

  1. design your class/API
  2. create a test suite
  3. implement the class/API
  4. run the test suite
  5. fix failures or errors and go to #4 again

It may seem that this will require a lot of time, but this impression is wrong. Creating the test suite using PHPUnit needs only a few minutes and running the test suite only seconds.

Design a class

Let's start with a small example: a string class. First we create a bunch of functions declarations to work on a string:

---- 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) {
    }
}
?>

Creating test suite

Now we can create a test suite, which checks every function of your string class. A test suite is normal PHP class inherited from PHPUnit_TestCase containing test functions, identified by a leading 'test' in the function name. In the test function an expected value has to be compared with the result of the function to test. The result of this compare must delegate to a function of the assert*()-family, which decides if a function passes or fails the test.

---- 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);
    }
  }
?>

The first test run

Now, we can run a first test. Make sure that all the paths are correct and then execute this PHP program.

---- stringtest.php ----

<?php

require_once 'testcase.php';
require_once 'PHPUnit.php';

$suite  = new PHPUnit_TestSuite("StringTest");
$result = PHPUnit::run($suite);

echo $result -> toString();
?>

If you call this script from the commandline, you will get the following output:

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

Every function fails the test, because your string functions didn't returned what we defined as the expected value.

If you want to call the script through your browser, you have to put the script in a correct html page and call $result->toHTML() instead of $result->toString().

Implementation

Ok, let's start with implementation of the our string class.

---- 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;
    }
}
?>

The implementation is complete and we can run the test again:

~>
php -f stringtest.php

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

D'oh! the last test failed! We made a typing mistake. Change line 16 in string.php to

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

and run the test again:

~>
php -f stringtest.php

TestCase stringtest->testtostring() passed
TestCase stringtest->testcopy() passed
TestCase stringtest->testadd() passed

Everything is now OK!

Conclusion

Does it seem like a lot of work for testing three simple functions? Don't forget, this is a small example. Think about bigger, more complex API's like database abstraction or basket classes in a shop application. PHPUnit is an excellent tool to detect errors in the implementation of your class.

Often you will want to reimplement or refactor a large class which is used in several different applications. Without a test suite the likeliness of you breaking something in one of the applications that depends on your class is very high. Thanks to unit tests, you can create a test suite for your class, and then reimplement your class with the security of knowing that as long as the new class passes the tests, applications that depend on the class will work.

Used source: http://pear.php.net

幻想少年梦 2024-10-12 20:45:39

如果可能的话,我真的建议从命令行运行 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);

I would really recomment running PHPUnit from Command Line, if possible. At our Company, it is not possible, but we are trying, wich makes our Tests unstable ...

I assume you have to setup some include paths for php with set_include_path(), so phpunit finds the rest of your files. But that may not be enough ...

Our code looks something like this

// 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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文