开始使用PHPUnit

想试一下单元测试很久了,但是一直没有合适的项目,而且中文网络上的PHPUnit教程要么太旧,要么太乱,所以总也没学会。最近准备把手头的项目重构一下,决定开始使用PHPUnit做单元测试,先照着PHPUnit的官网做了一下Tutorial,虽然已经很简单了,仍然被卡住几次,所以写篇文章记录一下。因为对PHP的包管理系统不熟悉,这篇文章会从安装开始。


1.安装

PHPUnit如果使用PHAR安装的话很简单。Phar归档就像Java的Jar,可以直接被PHP解释器执行。在*nix系统下,可以执行下面三条命令:

➜ wget https://phar.phpunit.de/phpunit.phar
➜ chmod +x phpunit.phar
➜ sudo mv phpunit.phar /usr/local/bin/phpunit

考虑到这次的重构会引入比较多类库,我选择了Composer做依赖管理。我在Windows上试过PhpStorm里的Composer,总是失败,感觉是网络不好的原因。这次在Ubuntu下安装很顺利,全局安装Composer之后,在命令行执行

composer global require phpunit/phpunit

全局安装PHPUnit。然后在~/.bashrc文件末尾加一行PATH=$PATH:/home/feng/.composer/vendor/bin(注意替换用户名),来将Composer的global bin目录加入PATH。

安装过后运行phpunit --version看到版本信息则说明安装成功。

另外,装完以后我发现Ubuntu系统可以使用apt-get install phpunit来安装,但我没有试过。

在Windows下我用的是XAMPP环境,其中已经内置PHPUnit了。如果要在命令提示符下使用的话,可以修改环境变量中的PATH,在里面加上C:\xampp\php(或者你修改后的路径)。再打开命令提示符,运行phpunit --version看一下。


2.第一个测试

第一个Tutorial我使用的是PHPUnit官网上的Getting Started,这里写的比它还要简单一点。

项目的目录结构如下:

├── phpunit.xml
├── src
│   ├── autoload.php
│   └── Money.php
└── tests
    └── MoneyTest.php

第一个文件是项目代码src/Money.php,内容如下:

<?php

class Money
{
    private $amount;

    public function __construct($amount)
    {
        $this->amount = $amount;
    }

    public function getAmount()
    {
        return $this->amount;
    }

    public function negate()
    {
        return new Money(-1*$this->amount);
    }
}

与之对应的单元测试是tests目录下的MoneyTest.php,注意单元测试文件名最好是*Test.php,这样以后指定tests目录便可以执行目录下的所有测试。

<?php

class MoneyTest extends PHPUnit_Framework_TestCase
{
    public function testCanBeNegated()
    {
        $a = new Money(1);

        $b = $a->negate();

        $this->assertEquals(-1, $b->getAmount());
    }
}

代码很简单,$this->assertEquals(-1, $b->getAmount());即断言后一个参数的执行结果与前一个参数相等,其他不解释了。

现在,如果在MoneyTest.php里加一行include_once('../src/Money.php');。然后在项目根目录下执行phpunit tests/MoneyTest,就可以看到执行结果了。


3.自动载入

但是,逐个添加include的方式太不方便,最好是能自动include所需的文件,PHPUnit提供了一个参数--bootstrap,可以使用项目的autoload文件。这里我自己写了一个最简单的autoload.php,只要4行。这个文件并不是PHPUnit专用的,应该放在src目录下。

<?php

function __autoload($class){
    include $class.'.php';
}

spl_autoload_register('__autoload');

当需要Money类时,就去include Money.php。写完__autoload()函数之后要用spl_autoload_register()注册上。

现在就可以去掉MoneyTest.php中的include语句,使用phpunit --bootstrap src/autoload.php tests/MoneyTest来执行测试了。


虽然可以自动载入,但是要执行的命令更长了。我们还可以写一个配置文件来为项目指定bootstrap,这样就不用每次都写在命令里了。

配置文件phpunit.xml放在项目根目录下。

<phpunit bootstrap="src/autoload.php">
</phpunit>

如果要执行MoneyTest,在项目根目录下执行:phpunit tests/MoneyTest
如果要执行tests目录下的所有测试,在项目根目录下执行:phpunit tests


Reference:

  1. Getting Started with PHPUnit – The PHP Testing Framework
  2. PHP: spl_autoload_register – Manual
  3. PHPUnit Bootstrap and Autoloading classes – Jess Telford
  4. Composer

开始使用PHPUnit》有8个想法

  1. 我只是贫困生

    您好,我想问一下,能否被测试的对象是仅仅只是一个函数呢?网上的数据太少,所以函数的主体均是一个类,这让我很不好操作,多谢。请告诉一下。

    回复
    1. fengchang 文章作者

      跟类还是函数没关系,Test 类可以随意命名,里面的测试代码不需要 new 对象,直接调函数 assert 就可以了。
      另外可能需要手动 include 文件

      回复

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注