PHPUnit 是 PHP 语言中最著名的单元测试框架,我们先来看一下 Laravel 官方文档对测试的介绍:
Laravel
天生就具有测试的基因。事实上,Laravel
默认就支持用PHPUnit
来做测试,并为你的应用程序配置好了phpunit.xml
文件。框架还提供了一些便利的辅助函数,让你可以更直观的测试你的应用程序。 默认情况,你的应用tests
目录中包含两个子目录:Feature
和Unit
。单元测试是针对你的代码中非常少,而且相对独立的一部分代码来进行的测试。实际上,大部分单元测试都是针对单个方法进行的。功能测试是针对大面积代码进行的测试,包括多个对象之间的交互,甚至是对JSON
端点的完整HTTP
请求。Feature
和Unit
目录中都提供一个ExampleTest.php
测试示例文件。安装一个新的Laravel
应用程序之后,在命令行下运行phpunit
命令,即可运行测试。
打开我们新创建的项目,可以看到测试目录如下:
所以我们可以直接运行测试:
$ phpunit
效果如下:
在使用 phpunit
进行测试时,Laravel
将根据 phpunit.xml
文件的配置来设置测试环境,我们来详细看一下该文件:
phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app</directory>
</whitelist>
</filter>
<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_DRIVER" value="log"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
</php>
</phpunit>
文件的第一行是 XML 文件的版本和编码描述信息,从第二行开始的 <phpunit>
元素包含的是正式的配置信息,在该元素里面还定义了其它子元素,例如testsuites
、filter
、php
环境变量等其它信息。下面我们逐一来介绍这些元素和属性。
通用配置
首先来看 <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
过滤器
另外,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
,表示会同步执行推送到队列的任务。