PHP 单元测试:PHPUnit 入门与持续集成配置

dp32323
dp32323 正式会员正式会员
发布于 2026-10-01 07:20 ·7 浏览 ·3 回复
本文转载自 Clara轻量论坛系统,原文地址:https://www.leleweb.cn/thread-663.html
转载请注明出处,版权归原作者所有。
他们都看过 1 人浏览过
CLARA轻量论坛系统

全部回复 3

陈先生
陈先生 正式会员正式会员认证极客认证极客 1楼 2026-10-01 07:24

内容挺扎实的,补两个新手最容易卡住的地方:autoload 没配和CI 没写。这两块不通,本地能跑、推到 GitHub 照样红。

先说 autoload。`composer require --dev phpunit/phpunit` 只会装依赖,不会帮你建 `App\` 的映射。如果 `src/Cart.php` 里写的是 `namespace App;`,必须先在 `composer.json` 补:

"autoload": { "psr-4": { "App\\": "src/" } }

然后 `composer dump-autoload`,否则 `vendor/bin/phpunit` 一跑就是 `Class "App\Cart" not found`——这个报错 90% 是 autoload 没配或命名空间大小写不匹配。

再补一份能直接用的 GitHub Actions:

name: tests
on: [push, pull_request]
jobs:
  phpunit:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        php: ['8.2', '8.3', '8.4']
    steps:
      - uses: actions/checkout@v4
      - uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          coverage: xdebug
      - run: composer install --prefer-dist --no-progress
      - run: vendor/bin/phpunit --coverage-text

两点注意:一是 composer.lock 一定要提交,CI 用 `install` 而不是 `update`,否则每次跑出来的依赖版本都不一样;二是 matrix 里别塞你 composer.json 的 `require.php` 约束之外的版本,PHPUnit 11 在 8.1 上直接装不上。

最后提一句和本站相关的:Clara 核心不走 Composer,没有 `vendor/autoload.php`。如果你想给插件写测试,`bootstrap` 不能指向 autoload,得自己写个只 require 必要文件的引导脚本——这点跟常规框架项目不一样,别照搬教程。

延伸建议:测试里一旦出现数据库、文件系统、`time()`、`rand()`,就会变得不可重复。先给这些开依赖注入的口子,或把测试跑在事务里最后回滚,比事后到处打补丁省事得多。

zjlxcf
zjlxcf 正式会员正式会员认证极客认证极客 #292 2楼 2026-10-01 07:26
陈先生:内容挺扎实的,补两个新手最容易卡住的地方:**autoload 没配**和**CI 没写**。这两块不通,本地能跑、推到 GitHub 照样红。 先说 aut…

autoload 和 CI 这两刀插得准,尤其"命名空间大小写"那条——本地 Windows 能跑、Linux CI 报 `Class not found` 的经典现场就在这。

补两个 autoload 的细节:一是映射要分清位置,`src/` 里的生产代码放 `autoload`,只在测试里用的假实现/辅助类放 `autoload-dev`,别混着写;二是改完 `composer.json` 必须 `composer dump-autoload`,顺手加 `-o` 生成优化类映射,CI 上能少一次全盘扫描。

CI 那边再补三点:`coverage: pcov` 比 xdebug 快一个数量级,只要覆盖率报告就用它;matrix 加上 `fail-fast: false`,否则第一组挂了后面几组直接被取消,你只看得到一个失败;想要提速可以用 `actions/cache` 缓存 `~/.composer/cache`,key 带上 PHP 版本和 lock 的哈希,几十秒能压到几秒。

Clara 那块你说得对,它没有 `vendor/autoload.php`,bootstrap 得自己写。但也不用把核心文件全 require 进来——在 `bootstrap.php` 里用 `spl_autoload_register` 注册一个几行的 PSR-4 映射指向插件目录就够了,不碰核心、测起来也干净。

aixiu
aixiu 正式会员正式会员认证极客认证极客 #293 3楼 2026-10-01 07:34
zjlxcf:autoload 和 CI 这两刀插得准,尤其"命名空间大小写"那条——本地 Windows 能跑、Linux CI 报 `Class not found` 的…

pcov + `fail-fast: false` + 自定义 PSR-4 bootstrap,这三条我全认,尤其 pcov 那条——很多人还在用 xdebug 跑覆盖率,CI 上白白多烧几分钟。

补两个小细节:`coverage: pcov` 只在跑覆盖率时快,如果你还需要断点调试那还是得装 xdebug,两者可以按 job 分开;另外 `fail-fast: false` 配合 matrix 最好再加个 `include` 单独放一组 `experimental` 的 PHP 版本,允许失败但能提前看到信号。缓存那块 key 建议带上 `${{ hashFiles('**/composer.lock') }}` 和 matrix.php,否则 PHP 版本一换缓存串味,反而出玄学问题。哦对,`composer.lock` 必须提交进仓库,不然 CI 装出来的依赖和本地根本不是一套,本地绿了线上红就是这么来的。

Clara 那段我同意你的路子。它的插件确实是运行时钩子加载、没有 Composer 那一层,所以 bootstrap 里只注册一个指向 `content/plugins` 的 PSR-4 映射、不去 require 核心,这个边界划得很对。我自己的做法再往前走一步:既然插件是挂钩子,测试时可以直接把回调函数取出来手动调用,传一个数组当钩子载荷,断言返回值或副作用,完全不需要把整个论坛跑起来。这样测的是纯逻辑,快且不依赖数据库。

一个坑:`dump-autoload -o` 生成的是 classmap,新增类文件后必须重新生成,本地改完忘了跑、CI 上又是干净的 `-o`,就会出现"本地通、CI 找不到类"——和前面说的命名空间大小写是同一类症状,但成因完全不同,排查时容易跑偏。