mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-08-31 05:05:33 +08:00
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
74 lines
2.9 KiB
PHP
74 lines
2.9 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace tests\Feature;
|
||
|
||
use app\common\test\TestCase;
|
||
use PHPUnit\Framework\AssertionFailedError;
|
||
use ReflectionMethod;
|
||
use think\facade\Config;
|
||
|
||
/**
|
||
* 隔离机制冒烟测试.
|
||
*
|
||
* 验证 TestCaseBase 的两个核心契约:
|
||
* 1. 事务回滚隔离真正生效(探针行跨测试不残留)
|
||
* 2. 安全校验拦截非测试库(拒绝连生产库)
|
||
*
|
||
* 继承 app 层入口 app\common\test\TestCase(Base/App 铁律:业务测试不直接继承 Base)。
|
||
*/
|
||
class IsolationSmokeTest extends TestCase
|
||
{
|
||
/**
|
||
* 探针自验证:先断言不存在→插入→断言可见.
|
||
*
|
||
* 完整契约依赖 tearDown 的 Db::rollback():本用例插入的探针行必须被回滚撤销,
|
||
* 从而【下次运行】本用例时第 1 步"不存在"断言才能成立。
|
||
* 单次运行验证写入路径;连续两次运行验证回滚隔离。
|
||
*/
|
||
public function test_isolation_probe_rolls_back(): void
|
||
{
|
||
// assertIsolationWorks 内部完成:missing → insert → has 三段断言。
|
||
$this->assertIsolationWorks();
|
||
|
||
// 显式成功标记(assertIsolationWorks 不带返回值,避免 risky test 告警)。
|
||
$this->assertTrue(true, 'isolation probe inserted and is visible within the transaction');
|
||
}
|
||
|
||
/**
|
||
* 拒绝非测试库:临时把连接库名改为不含 "test" 的值,
|
||
* 反射调用 protected assertTestDatabase 应触发 fail()。
|
||
*
|
||
* 使用 try/catch/finally 而非 expectException,目的是无论是否抛出
|
||
* 都能在 finally 中恢复 config,避免污染后续测试。
|
||
*/
|
||
public function test_refuses_non_test_database(): void
|
||
{
|
||
// think 的 Config::set 不支持点号多级路径(见 bootstrap 注释),
|
||
// 必须像 bootstrap 那样整段 pull 出来改了再 set 回去。
|
||
$dbConfig = Config::get('database');
|
||
$backup = is_array($dbConfig) ? $dbConfig : [];
|
||
|
||
$thrown = null;
|
||
try {
|
||
$dbConfig['connections']['main']['database'] = 'ulthon_admin_production_safe_marker';
|
||
Config::set($dbConfig, 'database');
|
||
|
||
// 反射调用 protected assertTestDatabase(setUp 里已自动调过一次并通过,
|
||
// 这里在事务内二次校验非测试库名,应当 fail)。
|
||
$method = new ReflectionMethod(self::class, 'assertTestDatabase');
|
||
$method->setAccessible(true);
|
||
$method->invoke($this);
|
||
} catch (AssertionFailedError $e) {
|
||
$thrown = $e;
|
||
} finally {
|
||
// 无论是否抛出,恢复 config —— 不污染同一进程后续测试。
|
||
Config::set($backup, 'database');
|
||
}
|
||
|
||
$this->assertNotNull($thrown, 'assertTestDatabase should fail when database name lacks "test"');
|
||
$this->assertStringContainsString('non-test database', $thrown->getMessage());
|
||
}
|
||
}
|