PHPUnit 是 PHP 语言中最著名的单元测试框架,我们先来看一下 Laravel 官方文档对测试的介绍:

Laravel 天生就具有测试的基因。事实上,Laravel 默认就支持用 PHPUnit 来做测试,并为你的应用程序配置好了 phpunit.xml 文件。框架还提供了一些便利的辅助函数,让你可以更直观的测试你的应用程序。 默认情况,你的应用 tests 目录中包含两个子目录:FeatureUnit。单元测试是针对你的代码中非常少,而且相对独立的一部分代码来进行的测试。实际上,大部分单元测试都是针对单个方法进行的。功能测试是针对大面积代码进行的测试,包括多个对象之间的交互,甚至是对 JSON 端点的完整 HTTP 请求。 FeatureUnit 目录中都提供一个 ExampleTest.php 测试示例文件。安装一个新的 Laravel 应用程序之后,在命令行下运行 phpunit 命令,即可运行测试。

打开我们新创建的项目,可以看到测试目录如下:

111 - 图1

所以我们可以直接运行测试:

  1. $ phpunit

效果如下:

111 - 图2

在使用 phpunit 进行测试时,Laravel 将根据 phpunit.xml 文件的配置来设置测试环境,我们来详细看一下该文件:

phpunit.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
  4. backupGlobals="false"
  5. backupStaticAttributes="false"
  6. bootstrap="vendor/autoload.php"
  7. colors="true"
  8. convertErrorsToExceptions="true"
  9. convertNoticesToExceptions="true"
  10. convertWarningsToExceptions="true"
  11. processIsolation="false"
  12. stopOnFailure="false">
  13. <testsuites>
  14. <testsuite name="Unit">
  15. <directory suffix="Test.php">./tests/Unit</directory>
  16. </testsuite>
  17. <testsuite name="Feature">
  18. <directory suffix="Test.php">./tests/Feature</directory>
  19. </testsuite>
  20. </testsuites>
  21. <filter>
  22. <whitelist processUncoveredFilesFromWhitelist="true">
  23. <directory suffix=".php">./app</directory>
  24. </whitelist>
  25. </filter>
  26. <php>
  27. <server name="APP_ENV" value="testing"/>
  28. <server name="BCRYPT_ROUNDS" value="4"/>
  29. <server name="CACHE_DRIVER" value="array"/>
  30. <server name="DB_CONNECTION" value="sqlite"/>
  31. <server name="DB_DATABASE" value=":memory:"/>
  32. <server name="MAIL_DRIVER" value="log"/>
  33. <server name="QUEUE_CONNECTION" value="sync"/>
  34. <server name="SESSION_DRIVER" value="array"/>
  35. </php>
  36. </phpunit>

文件的第一行是 XML 文件的版本和编码描述信息,从第二行开始的 <phpunit> 元素包含的是正式的配置信息,在该元素里面还定义了其它子元素,例如testsuitesfilterphp 环境变量等其它信息。下面我们逐一来介绍这些元素和属性。

通用配置

首先来看 <phpunit> 元素上的属性:

<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true"
>
  • bootstrap 属性对应命令行参数里面的 --bootstrap <file>,用于指定测试运行前需要引入的文件,这里配置为 vendor/autoload.php 表示会引入 Composer 自动加载和管理的所有依赖,以便在测试文件中使用。
  • colors 属性对应命令行参数里的 --colors=<flag>,用于指示在输出中是否用颜色进行标识。

这两个属性其实都可以在执行 phpunit 命令时通过命令行参数的形式传入,但配置到 phpunit.xml 中更方便,因为每次运行命令时这两个参数都不会变化。在<phpunit>元素中还可以配置其他 PHPUnit 的命令行参数,具体可以查看 官方文档,或者通过 phpunit --help 在命令行查看。

测试套件

Laravel 框架默认通过 <testsuites> 定义了两个 <testsuite> 测试套件,分别是用于单元测试的 Unit 和用于功能测试的 Feature

<testsuites>
    <testsuite name="Unit">
        <directory suffix="Test.php">./tests/Unit</directory>
    </testsuite>
    <testsuite name="Feature">
        <directory suffix="Test.php">./tests/Feature</directory>
    </testsuite>
</testsuites>

在它们各自的测试套件中,通过 directory 子元素指定对应测试文件所在的目录,并通过 suffix 属性指定测试文件的文件名后缀,这样,当运行 phpunit 命令时,PHPUnit 会从指定目录下匹配指定后缀的测试文件进行测试。

例如我们可以像下面这样运行测试:

$ phpunit --testsuite=Unit

111 - 图3

过滤器

另外,Laravel 框架还通过 <filter> 元素配置了过滤器:

<filter>
    <whitelist processUncoveredFilesFromWhitelist="true">
        <directory suffix=".php">./app</directory>
    </whitelist>
</filter>

在该元素中我们可以通过 whitelist 子元素指定用于配置代码覆盖率报告分析所使用的白名单。 Laravel 应用代码一般都位于项目根目录下的 app 目录中,并且我们只测试 PHP 代码。在 <whitelist> 中的 directory 子元素的配置可以很清楚地看出这些。

我们在运行 phpunit 时加上 --coverage-html . 参数,就可以在根目录下生成 HTML 格式的测试覆盖率报告文档了。

PHP 变量

最后,Laravel 框架还通过 <php> 元素为我们初始化了一些 PHPUnit 测试环境下的 PHP 常量:

<php>
    <server name="APP_ENV" value="testing"/>
    <server name="BCRYPT_ROUNDS" value="4"/>
    <server name="CACHE_DRIVER" value="array"/>
    <server name="DB_CONNECTION" value="sqlite"/>
    <server name="DB_DATABASE" value=":memory:"/>
    <server name="MAIL_MAILER" value="array"/>
    <server name="QUEUE_CONNECTION" value="sync"/>
    <server name="SESSION_DRIVER" value="array"/>
    <server name="TELESCOPE_ENABLED" value="false"/>
</php>

上述配置相当于以下 PHP 代码:

$_SERVER['APP_ENV'] = 'testing';
$_SERVER['BCRYPT_ROUNDS'] = '4';
$_SERVER['CACHE_DRIVER'] = 'array';
$_SERVER['DB_CONNECTION'] = 'sqlite';
$_SERVER['DB_DATABASE'] = ':memory:';
$_SERVER['MAIL_DRIVER'] = 'array';
$_SERVER['QUEUE_CONNECTION'] = 'sync';
$_SERVER['SESSION_DRIVER'] = 'array';
$_SERVER['TELESCOPE_ENABLED'] = 'false';

通过上述配置我们可以得知,在 Laravel 测试环境下,APP_ENV 的值是 testing,并且测试使用的是 sqlite 的内存数据库,这样我们测试时的数据不会干扰到我们的开发环境,并且我们在内存中测试,速度会更快一些。

缓存、邮件、会话驱动都是通过数组模拟,因而不会持久化到硬盘,此外队列驱动是 sync,表示会同步执行推送到队列的任务。