Swoft2 框架精华教程: Swoft 组件开发单元测试
- 作者: 刘杰
- 来源: 技术那些事
- 阅读:105
- 发布: 2025-06-16 17:04
- 最后更新: 2025-08-23 07:00
单元测试主要组成部分
swoft 组件单元测试示例
测试相关代码全部在 test 目录中
-
config
为测试用例中所用到的配置(根据项目需要添加)
-
testing
测试中需要加载的一些辅助相关的工具或者类
-
unit
单元测试主要目录,根据 phpunit 配置,类后需要有 Test.php 后缀,类中的方法跟被测试的类命名一致,需要加前缀 test。如原方法 CloudStorage::upload,单元测试为 CloudStorageTest::testUpload。
-
bean.php
因为是开发的 swoft 组件,所以 bean.php 为 bean 的定义文件,表示框架启动后自动实例化的 bean 实例。
-
bootstrap.php
启动文件
phpunit/phpunit 扩展(核心部分,具体运行单元测试)
可以通过 composer 的 require-dev 配置开发的依赖(见最后 composer 配置文件示例)。
phpunit.xml
用来执行单元测试的 xml 配置文件。具体配置说明可参见:https://docs.phpunit.de/en/8.5/configuration.html
示例:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
bootstrap="test/bootstrap.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="test">
<directory suffix="Test.php">./test/unit</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src/*</directory>
</whitelist>
</filter>
</phpunit>
composer.json
通过自定义 composer 命令 test 来触发单元测试的执行。
json
{
"name": "swoft/cloud-storage",
"type": "library",
"version": "v2.0.1",
"keywords": [
"php",
"swoole",
"swoft",
"cloud-storage",
"qiniu"
],
"description": "cloud storage component for swoft",
"homepage": "https://github.com/liujiekkk/swoft-cloud-storage",
"license": "Apache-2.0",
"require": {
"php": ">=7.4",
"qiniu/php-sdk": "^7.14",
"swoft/framework": "~2.0.0"
},
"autoload": {
"psr-4": {
"Swoft\\CloudStorage\\": "src/"
}
},
"require-dev": {
"phpunit/phpunit": "^7.5 || ^8.0",
"ext-json": "*"
},
"autoload-dev": {
"psr-4": {
"SwoftTest\\Unit\\": "vendor/swoft/framework/test/unit/",
"SwoftTest\\Testing\\": "vendor/swoft/framework/test/testing/",
"SwoftTest\\CloudStorage\\Unit\\": "test/unit",
"SwoftTest\\CloudStorage\\Testing\\": "test/testing"
}
},
"scripts": {
"test": "php run.php -c phpunit.xml"
}
}
注意:autoload-dev 中的 psr-4 开发目录和命名空间的绑定设置,只会包含当前项目。无论是此项目的直接依赖项目,还是直接依赖项目关联的间接依赖项目,其中的 autoload-dev psr-4 配置都不会合并到最终导出的命名空间中(可以查看命名空间的导出文件
当前项目/vendor/composer/autoload-psr4.php
)。另:composer 文件配置如果有变更,只有 composer update,composer install,composer dump-autoload 才会更新关联的命名空间配置。最好手动执行进行更新 composer dump-autoload。
composer 中的 autoload 配置,不管是项目本身,还是项目的直接依赖或者间接依赖,其中配置的命名空间都会导出到最终的 psr4 规范命名空间中。也就是说,不管是在开发测试脚本,还是正式项目代码中都可以通过 psr4 规范引用到相关类。
bash
# 触发单元测试开始执行
composer test
run.php
启动代码示例:
php
<?php
/** For Swoole coroutine tests */
use Swoole\ExitException;
Co::set([
'log_level' => SWOOLE_LOG_INFO,
'trace_flags' => 0
]);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (version_compare('7.1.0', PHP_VERSION, '>')) {
fwrite(
STDERR,
sprintf(
'This version of PHPUnit is supported on PHP 7.1 and PHP 7.2.' . PHP_EOL .
'You are using PHP %s (%s).' . PHP_EOL,
PHP_VERSION,
PHP_BINARY
)
);
die(1);
}
if (!ini_get('date.timezone')) {
ini_set('date.timezone', 'UTC');
}
foreach ([
__DIR__ . '/../../autoload.php',
__DIR__ . '/../vendor/autoload.php',
__DIR__ . '/vendor/autoload.php'
] as $file
) {
if (file_exists($file)) {
define('PHPUNIT_COMPOSER_INSTALL', $file);
break;
}
}
unset($file);
if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
fwrite(
STDERR,
'You need to set up the project dependencies using Composer:' . PHP_EOL . PHP_EOL .
' composer install' . PHP_EOL . PHP_EOL .
'You can learn all about Composer on https://getcomposer.org/.' . PHP_EOL
);
die(1);
} else {
if (array_reverse(explode('/', __DIR__))[0] ?? '' === 'tests') {
$vendor_dir = dirname(PHPUNIT_COMPOSER_INSTALL);
$bin_unit = "{$vendor_dir}/bin/phpunit";
$unit_uint = "{$vendor_dir}/phpunit/phpunit/phpunit";
if (file_exists($bin_unit)) {
@unlink($bin_unit);
@symlink(__FILE__, $bin_unit);
}
if (file_exists($unit_uint)) {
@unlink($unit_uint);
@symlink(__FILE__, $unit_uint);
}
}
}
if (!in_array('-c', $_SERVER['argv'])) {
$_SERVER['argv'][] = '-c';
$_SERVER['argv'][] = __DIR__ . '/phpunit.xml';
}
require PHPUNIT_COMPOSER_INSTALL;
$status = 0;
srun(function () {
// Status
global $status;
try {
$status = PHPUnit\TextUI\Command::main(false);
} catch (ExitException $e) {
var_dump($e->getMessage());
$status = $e->getCode();
}
});
exit($status);
启动文件
bootstrap.php 示例,主要是启动 swoft application 应用,然后加载配置文件 bean.php 定义等等,类似主框架启动过程。注意 TestApplication 可以参考 vendor/swoft/framework/test/testing/ 目录下 TestApplication 类:
php
<?php declare(strict_types=1);
/**
* bootstrap.php
*
* 版权所有(c) 2025 刘杰(king.2oo8@163.com)。保留所有权利。
*
* 未经事先书面许可,任何单位或个人不得将本软件的任何部分以任何形式(包括但不限于复制、
* 传播、披露等)进行使用、传播或向第三方披露。
*
* @author 刘杰
* @contact king.2oo8@163.com
*/
use SwoftTest\Testing\TestApplication;
// vendor at package dir
$packagePath = dirname(__DIR__);
if (!file_exists($packagePath . '/vendor/autoload.php')) {
throw new RuntimeException('Please run the "composer install" to install the dependencies');
}
/** @var \Composer\Autoload\ClassLoader $loader */
require $packagePath . '/vendor/autoload.php';
$app = new TestApplication(__DIR__);
$app->run();
启动测试
composer test
命令,会触发通过 php 命令运行 phpunit 单元测试,相当于执行命令:
shell
# ./vendor/bin/phpunit 为 php 脚本
php ./vendor/bin/phpunit --configuration phpunit.xml