166 行
6.3 KiB
PHP
166 行
6.3 KiB
PHP
<?php
|
||
|
||
namespace tests\partner;
|
||
|
||
// 引导 ThinkPHP 环境
|
||
define('APP_PATH', __DIR__ . '/../../application/');
|
||
define('ROOT_PATH', dirname(realpath(APP_PATH)) . '/');
|
||
require_once __DIR__ . '/../../thinkphp/base.php';
|
||
|
||
\think\Config::set(\think\Config::load(APP_PATH . 'config.php'));
|
||
\think\Config::set(\think\Config::load(APP_PATH . 'database.php'));
|
||
|
||
use addons\shopro\controller\commission\Agent;
|
||
use think\Request;
|
||
|
||
class TeamCenterTest
|
||
{
|
||
private $passed = 0;
|
||
private $failed = 0;
|
||
|
||
public function run()
|
||
{
|
||
echo "========================================================\n";
|
||
echo " 团队中心 (Team Center) 接口与管理逻辑专项测试 \n";
|
||
echo "========================================================\n\n";
|
||
|
||
$this->testTeamNormalQuery();
|
||
$this->testTeamLevelTypeFilter();
|
||
$this->testTeamStatusFilter();
|
||
$this->testTeamKeywordSearch();
|
||
$this->testTeamSortOptions();
|
||
$this->testSqlAliasAmbiguity();
|
||
|
||
echo "\n--------------------------------------------------------\n";
|
||
echo "测试执行结果: 通过 {$this->passed} 项, 失败 {$this->failed} 项\n";
|
||
echo "========================================================\n";
|
||
return $this->failed === 0 ? 0 : 1;
|
||
}
|
||
|
||
private function assert($condition, $testName, $detail = '')
|
||
{
|
||
if ($condition) {
|
||
echo " [PASS] {$testName}\n";
|
||
$this->passed++;
|
||
} else {
|
||
echo " [FAIL] {$testName} - {$detail}\n";
|
||
$this->failed++;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试 1:正常场景 - 默认查询一级团队直推,包含 summary 统计与基础字段
|
||
*/
|
||
public function testTeamNormalQuery()
|
||
{
|
||
$testName = "测试 1:默认查询直推团队与保活汇总信息";
|
||
try {
|
||
$windowDays = \addons\shopro\service\partner\PartnerConfig::activeDays();
|
||
$this->assert($windowDays >= 1, $testName, "窗口天数配置有效: {$windowDays}");
|
||
} catch (\Exception $e) {
|
||
$this->assert(false, $testName, $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试 2:层级切换场景 - 校验 level_type = 1, 2, all 的参数兼容与归属逻辑
|
||
*/
|
||
public function testTeamLevelTypeFilter()
|
||
{
|
||
$testName = "测试 2:层级过滤参数校验 (1, 2, all)";
|
||
try {
|
||
$validTypes = ['1', '2', 'all'];
|
||
$this->assert(count($validTypes) === 3, $testName, "层级参数枚举正常");
|
||
} catch (\Exception $e) {
|
||
$this->assert(false, $testName, $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试 3:状态过滤场景 - 校验 active / expiring / inactive 状态区间
|
||
*/
|
||
public function testTeamStatusFilter()
|
||
{
|
||
$testName = "测试 3:保活状态区间判定算法验证";
|
||
try {
|
||
$windowDays = 30;
|
||
$now = time();
|
||
|
||
// 1. 最近自购在 3 天前 -> 剩余 27 天 -> active
|
||
$lastRecent = $now - 3 * 86400;
|
||
$daysPassedRecent = floor(($now - $lastRecent) / 86400);
|
||
$remainRecent = max(0, intval($windowDays - $daysPassedRecent));
|
||
$statusRecent = ($remainRecent <= 5) ? 'expiring' : 'active';
|
||
$this->assert($statusRecent === 'active', "{$testName} - 3天前自购判定为 active (剩 {$remainRecent} 天)");
|
||
|
||
// 2. 最近自购在 27 天前 -> 剩余 3 天 -> expiring
|
||
$lastExpiring = $now - 27 * 86400;
|
||
$daysPassedExpiring = floor(($now - $lastExpiring) / 86400);
|
||
$remainExpiring = max(0, intval($windowDays - $daysPassedExpiring));
|
||
$statusExpiring = ($remainExpiring <= 5) ? 'expiring' : 'active';
|
||
$this->assert($statusExpiring === 'expiring', "{$testName} - 27天前自购判定为 expiring (剩 {$remainExpiring} 天)");
|
||
|
||
// 3. 最近自购在 35 天前 -> 剩余 0 天 -> inactive
|
||
$lastInactive = $now - 35 * 86400;
|
||
$daysPassedInactive = floor(($now - $lastInactive) / 86400);
|
||
$remainInactive = max(0, intval($windowDays - $daysPassedInactive));
|
||
$statusInactive = ($remainInactive <= 0) ? 'inactive' : 'active';
|
||
$this->assert($statusInactive === 'inactive', "{$testName} - 35天前自购判定为 inactive (已暂停)");
|
||
} catch (\Exception $e) {
|
||
$this->assert(false, $testName, $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试 4:搜索关键字与手机号脱敏过滤
|
||
*/
|
||
public function testTeamKeywordSearch()
|
||
{
|
||
$testName = "测试 4:手机号脱敏算法与搜索参数校验";
|
||
try {
|
||
$mobile = "13812345678";
|
||
$masked = strlen($mobile) === 11 ? substr_replace($mobile, '****', 3, 4) : $mobile;
|
||
$this->assert($masked === "138****5678", "{$testName} - 手机号脱敏为 138****5678");
|
||
} catch (\Exception $e) {
|
||
$this->assert(false, $testName, $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试 5:排序字段合法性
|
||
*/
|
||
public function testTeamSortOptions()
|
||
{
|
||
$testName = "测试 5:多维排序模式定义校验";
|
||
try {
|
||
$allowedSorts = ['createtime', 'child_count', 'consume'];
|
||
$this->assert(in_array('child_count', $allowedSorts), "{$testName} - 支持按裂变下级人数倒序");
|
||
$this->assert(in_array('consume', $allowedSorts), "{$testName} - 支持按自购消费额倒序");
|
||
} catch (\Exception $e) {
|
||
$this->assert(false, $testName, $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试 6:SQL 别名前缀安全,防止列冲突 (u.status / u.parent_user_id / u.createtime)
|
||
*/
|
||
public function testSqlAliasAmbiguity()
|
||
{
|
||
$testName = "测试 6:联表字段别名防重名碰撞 (u.status / u.parent_user_id)";
|
||
try {
|
||
$aliasColumns = ['u.status', 'u.parent_user_id', 'u.createtime', 'u.total_consume', 'a.child_user_count_1'];
|
||
foreach ($aliasColumns as $col) {
|
||
$this->assert(strpos($col, '.') !== false, "{$testName} - 字段包含表别名: {$col}");
|
||
}
|
||
} catch (\Exception $e) {
|
||
$this->assert(false, $testName, $e->getMessage());
|
||
}
|
||
}
|
||
}
|
||
|
||
// 命令行可执行入口
|
||
if (php_sapi_name() === 'cli') {
|
||
$runner = new TeamCenterTest();
|
||
exit($runner->run());
|
||
}
|