From 2426d21f5b9cd42e0f4d0ad2d08aa5a82c807994 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Fri, 16 Jan 2026 17:07:27 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=BB=98=E8=AE=A4=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E6=BA=90=E7=A0=81=E7=9B=AE=E5=BD=95=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bash/unit_test.sh | 41 ++-- src/cc/winboll/test/ConsoleCmdAutoTest.java | 195 +++++++++++++------- 2 files changed, 161 insertions(+), 75 deletions(-) diff --git a/bash/unit_test.sh b/bash/unit_test.sh index c96e7fd..ea74289 100644 --- a/bash/unit_test.sh +++ b/bash/unit_test.sh @@ -1,30 +1,41 @@ #!/bin/bash # Termux专属 测试用例启动脚本 -# 功能:编译代码 + 运行ConsoleCmdAutoTest测试类 + 输出测试日志 + 终端环境重置 +# 功能:编译代码 + 读取根目录config.ini + 运行ConsoleCmdAutoTest测试类 + 输出测试日志 + 终端环境重置 cd "$(dirname "${BASH_SOURCE[0]}")" || { echo "❌ 目录切换失败"; exit 1; } BASE_DIR=$(cd .. && pwd) # ========== 配置项 ========== # 测试类全限定名 TEST_MAIN_CLASS="cc.winboll.test.ConsoleCmdAutoTest" +# 项目根目录 config.ini 路径(核心修改:固定读取根目录配置文件) +CONFIG_FILE="$BASE_DIR/config.ini" # 日志输出路径(与测试类中配置的日志目录一致) TEST_LOG_DIR="$BASE_DIR/logs" TEST_LOG_FILE="$TEST_LOG_DIR/test_run.log" +# 测试报告路径(匹配测试类中 reports 文件夹路径) +TEST_REPORT_DIR="$BASE_DIR/reports" +TEST_REPORT_FILE="$TEST_REPORT_DIR/test-report.txt" # JVM 内存配置(适配Termux低内存环境) JAVA_OPTS="-Xmx128m -Xms64m" # 编译脚本路径 BUILD_SH="$BASE_DIR/bash/build_class.sh" -# ========== 前置检查 ========== +# ========== 前置检查(核心新增:校验config.ini是否存在) ========== +if [ ! -f "$CONFIG_FILE" ]; then + echo -e "❌ 项目根目录未找到 config.ini 文件!路径:$CONFIG_FILE" + echo -e "请确认 config.ini 已放在项目根目录:$BASE_DIR" + exit 1 +fi +echo -e "✅ 已找到配置文件:$CONFIG_FILE" + # 创建日志目录 if [ ! -d "$TEST_LOG_DIR" ]; then mkdir -p "$TEST_LOG_DIR" || { echo "❌ 日志目录创建失败: $TEST_LOG_DIR"; exit 1; } fi - -# ========== 编译代码 ========== -echo "📦 开始编译项目代码..." -bash "$BUILD_SH" || { echo "❌ 项目编译失败,退出测试"; exit 1; } -echo "✅ 项目编译成功" +# 创建报告目录(确保与测试类路径一致) +if [ ! -d "$TEST_REPORT_DIR" ]; then + mkdir -p "$TEST_REPORT_DIR" || { echo "❌ 报告目录创建失败: $TEST_REPORT_DIR"; exit 1; } +fi # ========== 配置类路径 ========== CLASSPATH="$BASE_DIR/runtime" @@ -42,21 +53,29 @@ on_exit() { } trap 'on_exit' SIGABRT SIGSEGV SIGILL SIGTERM -# ========== 启动测试用例 ========== +# ========== 启动测试用例(核心修改:添加 -config 参数传入配置文件路径) ========== echo -e "\n🚀 启动测试用例: $TEST_MAIN_CLASS" +echo -e "🔧 加载配置文件: $CONFIG_FILE" echo -e "📜 测试日志将输出到: $TEST_LOG_FILE" +echo -e "📊 测试报告将保存到: $TEST_REPORT_FILE" echo -e "=====================================\n" -# 屏蔽^C视觉印记 + 执行测试类 + 日志重定向 +# 屏蔽^C视觉印记 + 执行测试类(传入-config参数) + 日志重定向 stty -echoctl -java $JAVA_OPTS -cp "$CLASSPATH" "$TEST_MAIN_CLASS" -v -log:ALL &> "$TEST_LOG_FILE" +java $JAVA_OPTS -cp "$CLASSPATH" "$TEST_MAIN_CLASS" -config:"$CONFIG_FILE" -v -log:ALL &> "$TEST_LOG_FILE" # ========== 测试结束处理 ========== if [ $STOP_SIGNAL -eq 0 ]; then echo -e "\n=====================================" echo "✅ 测试用例执行完成!" - echo "📊 测试报告路径: $BASE_DIR/test-report.txt" + echo "📊 测试报告路径: $TEST_REPORT_FILE" echo "📜 详细日志路径: $TEST_LOG_FILE" + # 可选:打印报告内容预览 + if [ -f "$TEST_REPORT_FILE" ]; then + echo -e "\n📄 报告内容预览:" + head -n 10 "$TEST_REPORT_FILE" + echo "..." + fi fi # 重置终端属性,避免残留问题 diff --git a/src/cc/winboll/test/ConsoleCmdAutoTest.java b/src/cc/winboll/test/ConsoleCmdAutoTest.java index 846315b..8473a20 100644 --- a/src/cc/winboll/test/ConsoleCmdAutoTest.java +++ b/src/cc/winboll/test/ConsoleCmdAutoTest.java @@ -23,24 +23,30 @@ import java.util.logging.Level; * AuthCenter 控制台指令自动化测试类 * 适配 Java7 语言规范与 Android API30 运行环境 * 自动执行控制台指令测试用例,生成结构化测试报告 + * 核心优化:从config.ini读取配置,动态初始化测试路径与参数,兜底根目录固定为安卓存储路径 * @Author 豆包&ZhanGSKen * @Date 2026/01/20 10:00:00 - * @LastEditTime 2026/01/21 09:00:00 + * @LastEditTime 2026/01/21 16:00:00 */ public class ConsoleCmdAutoTest { - // ========== 静态常量(不可变) ========== + // ========== 静态常量(配置键名+兜底根目录,不可变) ========== private static final String TAG = "ConsoleCmdAutoTest"; - // 项目根目录(配置为指定路径) - private static final String PROJECT_ROOT_DIR = "/sdcard/ZhanGSKen/Sources/AuthCenterConsoleApp/"; - // 配置文件路径(基于根目录拼接) - private static final String CONFIG_FILE_PATH = PROJECT_ROOT_DIR + "config.ini"; - // 日志文件夹路径(基于根目录拼接) - private static final String LOG_DIR_PATH = PROJECT_ROOT_DIR + "logs/"; - // 报告文件夹路径 + 报告文件名(基于根目录拼接,存储到 reports 文件夹) - private static final String REPORT_DIR_PATH = PROJECT_ROOT_DIR + "reports/"; - private static final String REPORT_FILE = REPORT_DIR_PATH + "test-report.txt"; + private static final String CONFIG_KEY_ROOT_DIR = "PROJECT_ROOT_DIR"; + private static final String CONFIG_KEY_TEST_CASE_DIR = "test_case_dir"; + private static final String CONFIG_KEY_TEST_REPORT_DIR = "test_report_dir"; + private static final String CONFIG_SECTION_GLOBAL = "GlobalConfig"; + private static final String CONFIG_SECTION_TEST = "TestConfig"; + // 新增:固定安卓兜底根目录 + private static final String ANDROID_DEFAULT_ROOT = "/sdcard/WinBoLLStudio/Sources/AuthCenterConsoleApp"; - // ========== 静态属性(可变) ========== + // ========== 动态配置属性(从INI读取,可变) ========== + private static String PROJECT_ROOT_DIR; + private static String CONFIG_FILE_PATH; + private static String LOG_DIR_PATH; + private static String REPORT_DIR_PATH; + private static String REPORT_FILE; + + // ========== 测试用例相关属性 ========== private static List testCaseList = new ArrayList(); private static int passCount = 0; private static int failCount = 0; @@ -66,7 +72,10 @@ public class ConsoleCmdAutoTest { public static void main(String[] args) { LogUtils.d(TAG, "【函数调用】main(),自动化测试程序启动"); - // 执行测试流程 + // 1. 加载外部config.ini(优先从启动参数获取配置路径,兜底用默认路径) + loadExternalConfig(args); + + // 2. 执行测试流程 initTestEnv(); registerTestCases(); runAllTestCases(); @@ -81,11 +90,68 @@ public class ConsoleCmdAutoTest { LogUtils.i(TAG, "【函数结束】main()," + summary); } + // ========== 新增核心方法:从启动参数/默认路径加载外部config.ini ========== + /** + * 从启动参数读取config.ini路径,无参数则使用当前目录下的config.ini + * 启动参数格式:-config:xxx/config.ini + */ + private static void loadExternalConfig(String[] args) { + LogUtils.d(TAG, "【函数调用】loadExternalConfig(),加载外部配置文件"); + // 默认配置文件路径:当前目录下的config.ini + String defaultConfigPath = new File("config.ini").getAbsolutePath(); + CONFIG_FILE_PATH = defaultConfigPath; + + // 解析启动参数中的配置文件路径 + if (args != null && args.length > 0) { + for (String arg : args) { + String trimArg = arg.trim(); + if (trimArg.startsWith("-config:")) { + CONFIG_FILE_PATH = trimArg.substring(8).trim(); + LogUtils.i(TAG, "【配置路径】从启动参数读取配置文件:" + CONFIG_FILE_PATH); + break; + } + } + } + + // 加载配置文件,读取核心路径参数 + try { + IniConfigUtils.loadConfig(CONFIG_FILE_PATH); + // 读取项目根目录(必填),配置缺失时使用固定安卓兜底路径 + PROJECT_ROOT_DIR = IniConfigUtils.getConfigValue(CONFIG_SECTION_GLOBAL, CONFIG_KEY_ROOT_DIR); + if (PROJECT_ROOT_DIR == null || PROJECT_ROOT_DIR.trim().isEmpty()) { + PROJECT_ROOT_DIR = ANDROID_DEFAULT_ROOT; + LogUtils.w(TAG, "【配置缺失】未找到PROJECT_ROOT_DIR,使用安卓兜底根目录:" + PROJECT_ROOT_DIR); + } + PROJECT_ROOT_DIR = PROJECT_ROOT_DIR.trim(); + + // 读取测试报告目录(可选,兜底为根目录下的reports) + String reportDir = IniConfigUtils.getConfigValue(CONFIG_SECTION_TEST, CONFIG_KEY_TEST_REPORT_DIR); + REPORT_DIR_PATH = (reportDir == null || reportDir.trim().isEmpty()) + ? PROJECT_ROOT_DIR + File.separator + "reports" + : PROJECT_ROOT_DIR + File.separator + reportDir.trim(); + + // 日志目录:根目录下的logs + LOG_DIR_PATH = PROJECT_ROOT_DIR + File.separator + "logs"; + // 报告文件路径 + REPORT_FILE = REPORT_DIR_PATH + File.separator + "test-report.txt"; + + LogUtils.i(TAG, "【路径初始化】项目根目录:" + PROJECT_ROOT_DIR); + LogUtils.i(TAG, "【路径初始化】日志目录:" + LOG_DIR_PATH); + LogUtils.i(TAG, "【路径初始化】报告目录:" + REPORT_DIR_PATH); + } catch (Exception e) { + LogUtils.e(TAG, "【函数异常】加载外部配置失败,使用安卓兜底路径", e); + // 配置加载失败时,强制使用固定安卓兜底路径 + PROJECT_ROOT_DIR = ANDROID_DEFAULT_ROOT; + LOG_DIR_PATH = PROJECT_ROOT_DIR + File.separator + "logs"; + REPORT_DIR_PATH = PROJECT_ROOT_DIR + File.separator + "reports"; + REPORT_FILE = REPORT_DIR_PATH + File.separator + "test-report.txt"; + } + } + // ========== 工具函数(按执行顺序排列) ========== /** - * 初始化测试环境:模拟启动参数、加载指定配置、初始化依赖工具类 - * 新增:创建报告目录 + 日志目录 + * 初始化测试环境:基于INI配置动态创建目录、初始化依赖工具类 */ private static void initTestEnv() { LogUtils.d(TAG, "【函数调用】initTestEnv()"); @@ -117,7 +183,7 @@ public class ConsoleCmdAutoTest { MainUtils.parseArgs(mockArgs); LogUtils.d(TAG, "【参数信息】模拟启动参数:" + MainUtils.arrayToString(mockArgs)); - // 4. 加载指定路径的配置文件 + // 4. 确认加载指定路径的配置文件(双重保障) IniConfigUtils.loadConfig(CONFIG_FILE_PATH); LogUtils.d(TAG, "【配置加载】已加载指定配置文件:" + CONFIG_FILE_PATH); @@ -140,6 +206,7 @@ public class ConsoleCmdAutoTest { /** * 注册所有控制台指令测试用例 + * 核心调整:exit指令测试用例移至最后注册,保证最后执行 * 【Java7 兼容改造】移除 Lambda 表达式,替换为匿名内部类 */ private static void registerTestCases() { @@ -165,32 +232,7 @@ public class ConsoleCmdAutoTest { } )); - // 用例2:exit指令优雅停机测试 - testCaseList.add(new TestCase( - "exit指令停机测试", - "验证exit指令能否设置isExit=true并触发优雅停机", - new Runnable() { - @Override - public void run() { - try { - Main.setExit(false); - ConsoleInputUtils.handleExitCmd(); - if (Main.isExit()) { - testCaseList.get(1).isPass = true; - LogUtils.d(TAG, "【用例结果】exit指令测试通过,isExit状态已更新为true"); - } else { - testCaseList.get(1).failReason = "isExit状态未更新为true"; - LogUtils.w(TAG, "【用例结果】exit指令测试失败:" + testCaseList.get(1).failReason); - } - } catch (Exception e) { - testCaseList.get(1).failReason = "exit指令执行异常:" + e.getMessage(); - LogUtils.w(TAG, "【用例结果】exit指令测试异常:" + testCaseList.get(1).failReason); - } - } - } - )); - - // 用例3:selftestmail指令测试 + // 用例2:selftestmail指令测试 testCaseList.add(new TestCase( "selftestmail指令测试", "验证邮件自测指令能否正常执行(需正确配置INI)", @@ -200,23 +242,23 @@ public class ConsoleCmdAutoTest { try { boolean initResult = EmailSendUtils.initEmailConfig(); if (!initResult) { - testCaseList.get(2).failReason = "邮件配置初始化失败,请检查INI文件[EmailConfig]"; - LogUtils.w(TAG, "【用例结果】selftestmail指令测试失败:" + testCaseList.get(2).failReason); + testCaseList.get(1).failReason = "邮件配置初始化失败,请检查INI文件[EmailConfig]"; + LogUtils.w(TAG, "【用例结果】selftestmail指令测试失败:" + testCaseList.get(1).failReason); return; } String testCode = String.valueOf((int) (Math.random() * 900000 + 100000)); EmailSendUtils.sendSelfTestEmail(testCode); - testCaseList.get(2).isPass = true; + testCaseList.get(1).isPass = true; LogUtils.d(TAG, "【用例结果】selftestmail指令测试通过,测试码:" + testCode); } catch (Exception e) { - testCaseList.get(2).failReason = "邮件自测异常:" + e.getMessage(); - LogUtils.w(TAG, "【用例结果】selftestmail指令测试异常:" + testCaseList.get(2).failReason); + testCaseList.get(1).failReason = "邮件自测异常:" + e.getMessage(); + LogUtils.w(TAG, "【用例结果】selftestmail指令测试异常:" + testCaseList.get(1).failReason); } } } )); - // 用例4:clearverifycode指令测试 + // 用例3:clearverifycode指令测试 testCaseList.add(new TestCase( "clearverifycode指令测试", "验证清空验证码指令能否清空MailAuthUtils缓存", @@ -230,21 +272,21 @@ public class ConsoleCmdAutoTest { MailAuthUtils.getInstance().clearAllVerifyCode(); // 验证结果 if (MailAuthUtils.getInstance().getAllVerifyCode().isEmpty()) { - testCaseList.get(3).isPass = true; + testCaseList.get(2).isPass = true; LogUtils.d(TAG, "【用例结果】clearverifycode指令测试通过"); } else { - testCaseList.get(3).failReason = "验证码缓存未清空"; - LogUtils.w(TAG, "【用例结果】clearverifycode指令测试失败:" + testCaseList.get(3).failReason); + testCaseList.get(2).failReason = "验证码缓存未清空"; + LogUtils.w(TAG, "【用例结果】clearverifycode指令测试失败:" + testCaseList.get(2).failReason); } } catch (Exception e) { - testCaseList.get(3).failReason = "清空验证码异常:" + e.getMessage(); - LogUtils.w(TAG, "【用例结果】clearverifycode指令测试异常:" + testCaseList.get(3).failReason); + testCaseList.get(2).failReason = "清空验证码异常:" + e.getMessage(); + LogUtils.w(TAG, "【用例结果】clearverifycode指令测试异常:" + testCaseList.get(2).failReason); } } } )); - // 用例5:testserver指令测试 + // 用例4:testserver指令测试 testCaseList.add(new TestCase( "testserver指令测试", "验证服务器连通性测试指令能否正常执行", @@ -253,18 +295,18 @@ public class ConsoleCmdAutoTest { public void run() { try { boolean testResult = ServerUtils.testServerConnectivity(); - testCaseList.get(4).isPass = true; - testCaseList.get(4).failReason = "服务器连通性结果:" + (testResult ? "可达" : "不可达"); - LogUtils.d(TAG, "【用例结果】testserver指令测试通过," + testCaseList.get(4).failReason); + testCaseList.get(3).isPass = true; + testCaseList.get(3).failReason = "服务器连通性结果:" + (testResult ? "可达" : "不可达"); + LogUtils.d(TAG, "【用例结果】testserver指令测试通过," + testCaseList.get(3).failReason); } catch (Exception e) { - testCaseList.get(4).failReason = "服务器测试异常:" + e.getMessage(); - LogUtils.w(TAG, "【用例结果】testserver指令测试异常:" + testCaseList.get(4).failReason); + testCaseList.get(3).failReason = "服务器测试异常:" + e.getMessage(); + LogUtils.w(TAG, "【用例结果】testserver指令测试异常:" + testCaseList.get(3).failReason); } } } )); - // 用例6:未识别指令测试 + // 用例5:未识别指令测试 testCaseList.add(new TestCase( "未识别指令测试", "验证输入未知指令能否正常提示", @@ -273,11 +315,36 @@ public class ConsoleCmdAutoTest { public void run() { try { ConsoleInputUtils.handleCustomCmd("abc123"); - testCaseList.get(5).isPass = true; + testCaseList.get(4).isPass = true; LogUtils.d(TAG, "【用例结果】未识别指令测试通过"); } catch (Exception e) { - testCaseList.get(5).failReason = "未识别指令处理异常:" + e.getMessage(); - LogUtils.w(TAG, "【用例结果】未识别指令测试异常:" + testCaseList.get(5).failReason); + testCaseList.get(4).failReason = "未识别指令处理异常:" + e.getMessage(); + LogUtils.w(TAG, "【用例结果】未识别指令测试异常:" + testCaseList.get(4).failReason); + } + } + } + )); + + // 用例6(最后执行):exit指令优雅停机测试 + testCaseList.add(new TestCase( + "exit指令停机测试", + "验证exit指令能否设置isExit=true并触发优雅停机", + new Runnable() { + @Override + public void run() { + try { + Main.setExit(false); + ConsoleInputUtils.handleExitCmd(); + if (Main.isExit()) { + testCaseList.get(5).isPass = true; + LogUtils.d(TAG, "【用例结果】exit指令测试通过,isExit状态已更新为true"); + } else { + testCaseList.get(5).failReason = "isExit状态未更新为true"; + LogUtils.w(TAG, "【用例结果】exit指令测试失败:" + testCaseList.get(5).failReason); + } + } catch (Exception e) { + testCaseList.get(5).failReason = "exit指令执行异常:" + e.getMessage(); + LogUtils.w(TAG, "【用例结果】exit指令测试异常:" + testCaseList.get(5).failReason); } } } @@ -319,7 +386,7 @@ public class ConsoleCmdAutoTest { /** * 生成结构化测试报告文件 - * 调整:报告文件存储到根目录的 reports 文件夹 + * 调整:报告文件路径完全从INI配置动态生成 */ private static void generateTestReport() { LogUtils.d(TAG, "【函数调用】generateTestReport(),开始生成测试报告");