|
| 1 | +## 25. 2019-06-17-Laravel 单元测试 phpunit.xml 目录结构及测试编排文件说明 |
| 2 | + |
| 3 | +### 目录结构 |
| 4 | +Laravel 框架基于 PHPUnit 提供了开箱即用的测试功能,对代码测试的支持非常有好: |
| 5 | + |
| 6 | +Laravel PHPUnit 测试 |
| 7 | + |
| 8 | +以 Laravel 5.8 为例,在框架初始化过程中通过 Composer 安装了 PHPUnit 7(也可以手动升级到 PHPUnit 8),并且在项目根目下创建了 tests 目录用于存放测试文件: |
| 9 | + |
| 10 | +Laravel测试目录结构 |
| 11 | + |
| 12 | +在该目录中包含的 Unit 和 Feature 子目录下存放的测试用例分别用于单元测试和功能测试,二者都是基于 PHPUnit 实现,对应的测试用例的根类都是 PHPUnit\Framework\TestCase。而 Broswer 目录下存放的则是基于 Laravel Dusk(底层基于 Selenium)实现的浏览器测试文件(后面我们再介绍)。 |
| 13 | + |
| 14 | +此外,在 Laravel 项目根目录下还有一个与 PHPUnit 息息县关的 phpunit.xml 文件,该文件我们在上篇教程中简单介绍过,是 PHPUnit 的编排文件,用于编排和初始化 PHPUnit 的测试行为,PHPUnit 在执行测试之前会基于这个文件进行初始化设置,你可以将其看作是 PHPUnit 的配置文件,下面我们就从这个文件为入口,分析 Laravel 框架如何集成 PHPUnit 进行单元测试和功能测试。 |
| 15 | + |
| 16 | +### 通过 phpunit.xml 编排 PHPUnit |
| 17 | +在上一篇 PHPUnit 入门教程中,我们已经介绍过,可以通过 XML 配置文件来编排 PHPUnit 的测试,对应的 XML 文件位于项目根目录下的 phpunit.xml,Laravel 框架已经为我们做好了如下初始化设置: |
| 18 | + |
| 19 | +<?xml version="1.0" encoding="UTF-8"?> |
| 20 | +<phpunit backupGlobals="false" |
| 21 | + backupStaticAttributes="false" |
| 22 | + bootstrap="vendor/autoload.php" |
| 23 | + colors="true" |
| 24 | + convertErrorsToExceptions="true" |
| 25 | + convertNoticesToExceptions="true" |
| 26 | + convertWarningsToExceptions="true" |
| 27 | + processIsolation="false" |
| 28 | + stopOnFailure="false"> |
| 29 | + <testsuites> |
| 30 | + <testsuite name="Unit"> |
| 31 | + <directory suffix="Test.php">./tests/Unit</directory> |
| 32 | + </testsuite> |
| 33 | + |
| 34 | + <testsuite name="Feature"> |
| 35 | + <directory suffix="Test.php">./tests/Feature</directory> |
| 36 | + </testsuite> |
| 37 | + </testsuites> |
| 38 | + <filter> |
| 39 | + <whitelist processUncoveredFilesFromWhitelist="true"> |
| 40 | + <directory suffix=".php">./app</directory> |
| 41 | + </whitelist> |
| 42 | + </filter> |
| 43 | + <php> |
| 44 | + <server name="APP_ENV" value="testing"/> |
| 45 | + <server name="BCRYPT_ROUNDS" value="4"/> |
| 46 | + <server name="CACHE_DRIVER" value="array"/> |
| 47 | + <server name="MAIL_DRIVER" value="array"/> |
| 48 | + <server name="QUEUE_CONNECTION" value="sync"/> |
| 49 | + <server name="SESSION_DRIVER" value="array"/> |
| 50 | + </php> |
| 51 | +</phpunit> |
| 52 | +该文件的第一行是 XML 文件的版本和编码描述信息,从第二行开始的 <phpunit> 元素则正式开始配置 PHPUnit 的核心功能,在该元素里面还嵌套定义了其它子元素,用于配置测试套件、过滤器、PHP 变量等其它信息。下面我们逐一来介绍这些元素和属性。 |
| 53 | + |
| 54 | +#### 通用配置 |
| 55 | +首先来看 phpunit 元素上的属性,其中很多属性其实都可以在执行 phpunit 命令时通过命令行参数的形式传入,但是如果参数太多,且每次传入参数都是一样的,显然配置到 phpunit.xml 中更方便,也更加易于维护,PHPUnit 执行的命令行参数可以在这里查看,或者通过 phpunit --help 在命令行查看: |
| 56 | + |
| 57 | +backupGlobals 属性对应命令行参数里的 --globals-backup,用于在每个测试中备份和恢复 PHP 超全局变量 $GLOBALS,这里设置为 false 表示不做相应的备份和恢复操作。 |
| 58 | +backupStaticAttributes 属性对应命令行参数里的 static-backup,用于在每个测试中备份和恢复静态属性,这里设置为 false 表示不做相应的备份和恢复操作。 |
| 59 | +bootstrap 属性对应命令行参数里面的 --bootstrap <file>,用于指定测试运行前需要引入的文件,这里配置为 vendor/autoload.php 表示会引入 Composer 自动加载和管理的所有依赖,以便在测试文件中使用。 |
| 60 | +colors 属性对应命令行参数里的 --colors=<flag>,用于指示在输出中是否用颜色进行标识。 |
| 61 | +processIsolation 属性对应命令行参数里的 --process-isolation,用于表示是否在隔离的 PHP 进程中执行测试。 |
| 62 | +stopOnFailure 属性对应命令行参数里的 --stop-on-failure,用于表示测试出错或失败时是否退出脚本执行,配置为 false 表示不退出。 |
| 63 | +接下来是一些不能通过命令行参数指定的属性: |
| 64 | + |
| 65 | +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 表示启用该功能。 |
| 66 | +convertNoticesToExceptions 属性用于定义是否将 PHP NOTICE 级别错误转化为异常,设置为 true 表示会将 E_NOTICE、E_USER_NOTICE、E_STRICT 三种级别错误转化为异常。 |
| 67 | +convertWarningsToExceptions 属性用于定义是否将 PHP WARNING 级别错误转化为异常,设置为 true 表示会将 E_WARNING 或 E_USER_WARNING 级别错误转化为异常。 |
| 68 | +当然,这里只包含了 PHPUnit 所支持的 phpunit 配置的一部分属性,更多配置请参考官方文档 及 PHPUnit 命令行参数配置。 |
| 69 | + |
| 70 | +#### 测试套件 |
| 71 | +接下来,我们看 Laravel 框架为我们默认配置的测试套件,它们定义在子元素 <testsuites> 中,在 PHPUnit 中,我们可以像上篇教程那样配置单个 <testsuite>,也可以像 Laravel 框架这样通过 <testsuites> 配置多个 <testsuite>,这取决于项目的复杂度或者你的需求。 |
| 72 | + |
| 73 | +Laravel 框架默认通过 <testsuites> 定义了两个 <testsuite>,分别是用于单元测试的 Unit 和用于功能的测试的 Feature,在它们各自的测试套件中,通过 directory 子元素指定对应测试文件所在的目录,并通过 suffix 属性指定测试文件的文件名后缀,这样,当运行 phpunit 命令时,PHPUnit 会从指定目录下匹配指定后缀的测试文件进行测试。 |
| 74 | + |
| 75 | +在运行 phpunit 命令时,我们可以通过相应测试套件的名称匹配要执行的测试用例: |
| 76 | + |
| 77 | + |
| 78 | + |
| 79 | +更多测试套件的配置选项可以参考官方文档。 |
| 80 | + |
| 81 | +#### 过滤器 |
| 82 | +另外,Laravel 框架还通过 <filter> 元素配置了过滤器,在该元素中我们可以通过 whitelist 子元素指定用于配置代码覆盖率报告分析所使用的白名单,代码覆盖率是代码测试中一个很重要的概念,我们的测试代码要尽可能覆盖到 100% 的业务代码,这样的测试才有意义,而 Laravel 应用代码都位于项目根目录下的 app 目录中,并且我们只测试 PHP 代码,所以在 <whitelist> 中通过 directory 子元素做了相应的配置。 |
| 83 | + |
| 84 | +这样,我们在运行 phpunit 时加上 --coverage-html . 参数,就可以在根目录下生成 HTML 格式的测试覆盖率报告文档了: |
| 85 | + |
| 86 | + |
| 87 | + |
| 88 | +打开对应的 index.html 文档,就可以在浏览器中看到测试覆盖率报告页面: |
| 89 | + |
| 90 | +Laravel PHPUnit 代码覆盖率 |
| 91 | + |
| 92 | +#### PHP 变量 |
| 93 | +最后,Laravel 框架还通过 <php> 元素为我们初始化了一些 PHPUnit 测试环境下的 PHP 常量: |
| 94 | + |
| 95 | +<php> |
| 96 | + <server name="APP_ENV" value="testing"/> |
| 97 | + <server name="BCRYPT_ROUNDS" value="4"/> |
| 98 | + <server name="CACHE_DRIVER" value="array"/> |
| 99 | + <server name="MAIL_DRIVER" value="array"/> |
| 100 | + <server name="QUEUE_CONNECTION" value="sync"/> |
| 101 | + <server name="SESSION_DRIVER" value="array"/> |
| 102 | +</php> |
| 103 | +上述配置相当于以下 PHP 代码: |
| 104 | + |
| 105 | +$_SERVER['APP_ENV'] = 'testing'; |
| 106 | +$_SERVER['BCRYPT_ROUNDS'] = '4'; |
| 107 | +$_SERVER['CACHE_DRIVER'] = 'array'; |
| 108 | +$_SERVER['MAIL_DRIVER'] = 'array'; |
| 109 | +$_SERVER['QUEUE_CONNECTION'] = 'sync'; |
| 110 | +$_SERVER['SESSION_DRIVER'] = 'array'; |
| 111 | +通过上述配置我们可以得知,在 Laravel 测试环境下,APP_ENV 的值是 testing,因此,我们可以在根目录下创建一个 .env.testing 文件作为测试环境下的环境配置文件,运行 phpunit 时实际执行的是控制台应用的 Kernel 来启动应用,这样,系统就会通过 .env.testing 读取环境配置。 |
| 112 | + |
| 113 | +缓存、邮件、会话驱动都是通过数组模拟,因而不会持久化到硬盘,此外队列驱动是 sync,表示会同步执行推送到队列的任务。 |
| 114 | + |
| 115 | +除此之外,还可以初始化 PHP 请求、常量、INI 设置、Cookie、超全局变量等信息,更多使用明细请参考官方文档。 |
| 116 | + |
| 117 | +如果需要的话,你还可以在 phpunit.xml 在编排 PHPUnit 的日志和监听器,由于 Laravel 框架默认没有提供这方面的配置,我们这里就不详细展开了,后面如果有用到会提及。 |
| 118 | + |
| 119 | +有了以上的概念和基础,下一篇我们将开始在 Laravel 框架中通过 PHPUnit 编写单元测试代码。 |
| 120 | + |
| 121 | +参考地址:[测试系列 —— 在 Laravel 中基于 PHPUnit 进行代码测试:目录结构及测试编排文件 phpunit.xml 详解](https://laravelacademy.org/post/19579.html) |
0 commit comments