在 Laravel 中基于 PHPUnit 进行代码测试:目录结构及测试编排文件 phpunit.xml 详解
目录结构
Laravel 框架基于 PHPUnit 提供了开箱即用的测试功能,对代码测试的支持非常有好:
以 Laravel 5.8 为例,在框架初始化过程中通过 Composer 安装了 PHPUnit 7(也可以手动升级到 PHPUnit 8),并且在项目根目下创建了 tests
目录用于存放测试文件:
在该目录中包含的 Unit
和 Feature
子目录下存放的测试用例分别用于单元测试和功能测试,二者都是基于 PHPUnit 实现,对应的测试用例的根类都是 PHPUnit\Framework\TestCase
。而 Broswer
目录下存放的则是基于 Laravel Dusk(底层基于 Selenium)实现的浏览器测试文件(后面我们再介绍)。
此外,在 Laravel 项目根目录下还有一个与 PHPUnit 息息县关的 phpunit.xml
文件,该文件我们在上篇教程中简单介绍过,是 PHPUnit 的编排文件,用于编排和初始化 PHPUnit 的测试行为,PHPUnit 在执行测试之前会基于这个文件进行初始化设置,你可以将其看作是 PHPUnit 的配置文件,下面我们就从这个文件为入口,分析 Laravel 框架如何集成 PHPUnit 进行单元测试和功能测试。
通过 phpunit.xml
编排 PHPUnit
在上一篇 PHPUnit 入门教程中,我们已经介绍过,可以通过 XML 配置文件来编排 PHPUnit 的测试,对应的 XML 文件位于项目根目录下的 phpunit.xml
,Laravel 框架已经为我们做好了如下初始化设置:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit 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="MAIL_DRIVER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
</php>
</phpunit>
该文件的第一行是 XML 文件的版本和编码描述信息,从第二行开始的 <phpunit>
元素则正式开始配置 PHPUnit 的核心功能,在该元素里面还嵌套定义了其它子元素,用于配置测试套件、过滤器、PHP 变量等其它信息。下面我们逐一来介绍这些元素和属性。
通用配置
首先来看 phpunit
元素上的属性,其中很多属性其实都可以在执行 phpunit
命令时通过命令行参数的形式传入,但是如果参数太多,且每次传入参数都是一样的,显然配置到 phpunit.xml
中更方便,也更加易于维护,PHPUnit 执行的命令行参数可以在这里查看,或者通过 phpunit --help
在命令行查看:
-
backupGlobals
属性对应命令行参数里的--globals-backup
,用于在每个测试中备份和恢复 PHP 超全局变量$GLOBALS
,这里设置为false
表示不做相应的备份和恢复操作。 -
backupStaticAttributes
属性对应命令行参数里的static-backup
,用于在每个测试中备份和恢复静态属性,这里设置为false
表示不做相应的备份和恢复操作。 -
bootstrap
属性对应命令行参数里面的--bootstrap <file>
,用于指定测试运行前需要引入的文件,这里配置为vendor/autoload.php
表示会引入 Composer 自动加载和管理的所有依赖,以便在测试文件中使用。 -
colors
属性对应命令行参数里的--colors=<flag>
,用于指示在输出中是否用颜色进行标识。 -
processIsolation
属性对应命令行参数里的--process-isolation
,用于表示是否在隔离的 PHP 进程中执行测试。 -
stopOnFailure
属性对应命令行参数里的--stop-on-failure
,用于表示测试出错或失败时是否退出脚本执行,配置为false
表示不退出。
接下来是一些不能通过命令行参数指定的属性:
-
convertErrorsToExceptions
属性用于定义是否将 PHP ERROR 级别错误转化为异常,默认会转化为异常的错误类型包括:E_WARNING
、E_NOTICE
、E_USER_ERROR
、E_USER_WARNING
、E_USER_NOTICE
、E_STRICT
、E_RECOVERABLE_ERROR
、E_DEPRECATED
、E_USER_DEPRECATED
,这里将该属性设置为true
表示启用该功能。 -
convertNoticesToExceptions
属性用于定义是否将 PHP NOTICE 级别错误转化为异常,设置为true
表示会将E_NOTICE
、E_USER_NOTICE
、E_STRICT
三种级别错误转化为异常。 -
convertWarningsToExceptions
属性用于定义是否将 PHP WARNING 级别错误转化为异常,设置为true
表示会将E_WARNING
或E_USER_WARNING
级别错误转化为异常。
当然,这里只包含了 PHPUnit 所支持的 phpunit
配置的一部分属性,更多配置请参考官方文档 及 PHPUnit 命令行参数配置。
测试套件
接下来,我们看 Laravel 框架为我们默认配置的测试套件,它们定义在子元素 <testsuites>
中,在 PHPUnit 中,我们可以像上篇教程那样配置单个 <testsuite>
,也可以像 Laravel 框架这样通过 <testsuites>
配置多个 <testsuite>
,这取决于项目的复杂度或者你的需求。
Laravel 框架默认通过 <testsuites>
定义了两个 <testsuite>
,分别是用于单元测试的 Unit
和用于功能的测试的 Feature
,在它们各自的测试套件中,通过 directory
子元素指定对应测试文件所在的目录,并通过 suffix
属性指定测试文件的文件名后缀,这样,当运行 phpunit
命令时,PHPUnit 会从指定目录下匹配指定后缀的测试文件进行测试。
在运行 phpunit
命令时,我们可以通过相应测试套件的名称匹配要执行的测试用例:
更多测试套件的配置选项可以参考官方文档。
过滤器
另外,Laravel 框架还通过 <filter>
元素配置了过滤器,在该元素中我们可以通过 whitelist
子元素指定用于配置代码覆盖率报告分析所使用的白名单,代码覆盖率是代码测试中一个很重要的概念,我们的测试代码要尽可能覆盖到 100% 的业务代码,这样的测试才有意义,而 Laravel 应用代码都位于项目根目录下的 app
目录中,并且我们只测试 PHP 代码,所以在 <whitelist>
中通过 directory
子元素做了相应的配置。
这样,我们在运行 phpunit
时加上 --coverage-html .
参数,就可以在根目录下生成 HTML 格式的测试覆盖率报告文档了:
打开对应的 index.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="MAIL_DRIVER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
</php>
上述配置相当于以下 PHP 代码:
$_SERVER['APP_ENV'] = 'testing';
$_SERVER['BCRYPT_ROUNDS'] = '4';
$_SERVER['CACHE_DRIVER'] = 'array';
$_SERVER['MAIL_DRIVER'] = 'array';
$_SERVER['QUEUE_CONNECTION'] = 'sync';
$_SERVER['SESSION_DRIVER'] = 'array';
通过上述配置我们可以得知,在 Laravel 测试环境下,APP_ENV
的值是 testing
,因此,我们可以在根目录下创建一个 .env.testing
文件作为测试环境下的环境配置文件,运行 phpunit
时实际执行的是控制台应用的 Kernel 来启动应用,这样,系统就会通过 .env.testing
读取环境配置。
缓存、邮件、会话驱动都是通过数组模拟,因而不会持久化到硬盘,此外队列驱动是 sync
,表示会同步执行推送到队列的任务。
除此之外,还可以初始化 PHP 请求、常量、INI 设置、Cookie、超全局变量等信息,更多使用明细请参考官方文档。
如果需要的话,你还可以在 phpunit.xml
在编排 PHPUnit 的日志和监听器,由于 Laravel 框架默认没有提供这方面的配置,我们这里就不详细展开了,后面如果有用到会提及。
有了以上的概念和基础,下一篇我们将开始在 Laravel 框架中通过 PHPUnit 编写单元测试代码。
1 Comment
coverage-html 这个要安装xdebug扩展