Swoft2 框架精华教程: Swoft 组件开发单元测试

单元测试主要组成部分

swoft 组件单元测试示例

Snipaste_2025-06-16_10-20-07.jpg

测试相关代码全部在 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