Files
ulthon_admin/tests/bootstrap.php
augushong 553047025c refactor(install): 种子退役,migrate:run 一条命令完成建表与初始数据
新增 InitDataAlignService 六域对齐(超管/角色/权限节点/配置/快捷入口/商城演示)与 20260909130000 迁移;SystemAdmin 快照以字面量哈希入库;删除种子三件与安装锁依赖,seeds 目录留 .gitkeep;README/tests/规则等 11 处说明同步。

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-09 14:38:10 +00:00

107 lines
5.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* PHPUnit 引导脚本.
*
* 职责:
* 1. require composer autoload
* 2. 引导 ThinkPHP 容器(App::initialize)
* 3. 【config 级覆盖】把默认连接 connections.main 指向测试库
* 4. 早期安全护栏:解析出的库名必须含 "test",否则拒绝运行
*
* 与 wkbox 衍生项目同构,但区别:
* - 连接参数从 .env 读取(hostname/hostport/username/password/charset/prefix),
* 复用开发库同实例的连接(典型单机 mysql,测试库仅库名不同)
* - 测试库名 = .env 中 DATABASE 值 + "_test" 后缀(如 ulthon_admin → ulthon_admin_test)
*
* 为什么用 config 级覆盖而不是环境变量:
* ThinkPHP 的 Env 组件加载 .env,且 .env 值【优先于】OS 环境变量(getenv 只是 fallback)。
* .env 里已存在 HOSTNAME/DATABASE/USERNAME/PASSWORD/HOSTPORT,putenv/$env:VAR/bash 前缀变量
* 都无法覆盖它们。唯一可靠覆盖点 = config 级:App::initialize() 之后直接改写
* config/database.php 解析出的连接数组。Db facade 运行时读 config,覆盖后所有 DB
* 操作都连测试库。
*
* 关键坑点(think 8):
* think\Config::set(array $config, ?string $name) 的 $name 只支持【单段一级配置名】,
* 不像 Config::get 那样解析点号多级路径。直接传 'database.connections.main' 会被当成
* 带点的字面顶层 key,根本没写进嵌套位置(静默失败)。
* 正确做法:把整段 'database' 配置 pull 出来 → 原地改 connections.main → set 回 'database'。
*
* 不在此做的事:
* - 不 require 全局 common.php(App::initialize() + autoload 已够引导 facade,
* helper.php 全局函数测试基建用不到)
* - 不开事务(事务隔离由 TestCaseBase.setUp 负责)
* - 不跑 migrate/scheme(由独立的 setup 脚本负责)
* - 不销毁容器(容器跨测试复用,tearDown 只回滚事务)
*/
declare(strict_types=1);
// ----------------------------------------------------------------------------
// 1. autoload + ThinkPHP 容器引导
// ----------------------------------------------------------------------------
require __DIR__ . '/../vendor/autoload.php';
$app = new \think\App();
$app->initialize();
// ----------------------------------------------------------------------------
// 2. 从 .env 读取连接参数,组装测试库连接配置
// 复用开发库同实例的连接参数(hostname/hostport/username/password/charset/prefix),
// 仅将 database 名替换为测试库名({原库名}_test)。
// ----------------------------------------------------------------------------
$envHostname = \think\facade\Env::get('database.hostname');
$envHostport = \think\facade\Env::get('database.hostport');
$envUsername = \think\facade\Env::get('database.username');
$envPassword = \think\facade\Env::get('database.password');
$envCharset = \think\facade\Env::get('database.charset');
$envPrefix = \think\facade\Env::get('database.prefix');
$envDatabase = \think\facade\Env::get('database.database');
// 测试库名策略:原库名 + _test 后缀(如 ulthon_admin → ulthon_admin_test)
$testDatabase = is_string($envDatabase) && $envDatabase !== ''
? $envDatabase . '_test'
: 'ulthon_admin_test';
// ----------------------------------------------------------------------------
// 3. config 级覆盖 connections.main 指向测试库
// 覆盖目标 = connections.main(本项目 config/database.php 默认连接是 main)。
// 保留框架自定义 query 类与其它运行时选项,只改"指向哪个库"的部分。
// ----------------------------------------------------------------------------
$dbConfig = \think\facade\Config::get('database');
if (!is_array($dbConfig)) {
$dbConfig = [];
}
$dbConfig['default'] = 'main';
if (!isset($dbConfig['connections']) || !is_array($dbConfig['connections'])) {
$dbConfig['connections'] = [];
}
if (!isset($dbConfig['connections']['main']) || !is_array($dbConfig['connections']['main'])) {
$dbConfig['connections']['main'] = [];
}
$dbConfig['connections']['main'] = array_merge(
$dbConfig['connections']['main'],
[
'type' => 'mysql',
'hostname' => is_string($envHostname) && $envHostname !== '' ? $envHostname : '127.0.0.1',
'hostport' => is_string($envHostport) && $envHostport !== '' ? $envHostport : '3306',
'database' => $testDatabase,
'username' => is_string($envUsername) && $envUsername !== '' ? $envUsername : 'root',
'password' => is_string($envPassword) ? $envPassword : '',
'charset' => is_string($envCharset) && $envCharset !== '' ? $envCharset : 'utf8mb4',
'prefix' => is_string($envPrefix) && $envPrefix !== '' ? $envPrefix : 'ul_',
'fields_cache' => false,
],
// 必须保留框架自定义 query 类,否则 ORM 行为异常。
['query' => \app\common\provider\db\Query::class],
);
\think\facade\Config::set($dbConfig, 'database');
// ----------------------------------------------------------------------------
// 4. 早期安全护栏:在任何测试运行前,确认解析出的库名含 "test"
// (TestCaseBase.setUp 会再校验一次;这里更早触发,防患于未然)
// ----------------------------------------------------------------------------
$resolvedDb = \think\facade\Config::get('database.connections.main.database');
if (!is_string($resolvedDb) || stripos($resolvedDb, 'test') === false) {
throw new \RuntimeException('Test bootstrap refusing non-test database: ' . $resolvedDb);
}