netrans/test/run_tests.py

346 lines
12 KiB
Python
Executable File
Raw Permalink 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.

"""
主测试运行器
统一运行所有测试并生成综合报告
"""
import sys
import unittest
import time
import argparse
from pathlib import Path
from typing import List, Dict, Any, Optional
import json
# 添加测试基础模块
sys.path.insert(0, str(Path(__file__).parent / "netrans_api" / "unit"))
sys.path.insert(0, str(Path(__file__).parent / "netrans_api" / "integration"))
from test_base import TestReporter
import signal
import threading
from contextlib import contextmanager
@contextmanager
def timeout_context(seconds):
"""跨平台超时上下文管理器"""
if seconds is None:
yield
return
# 使用线程定时器实现超时
timeout_occurred = threading.Event()
def timeout_handler():
timeout_occurred.set()
timer = threading.Timer(seconds, timeout_handler)
timer.start()
try:
yield timeout_occurred
finally:
timer.cancel()
from test_core_functions import (
TestNetransCore,
TestModelMetadata
)
from test_quantize_types import TestQuantizerTypes
from test_integration import (
TestCompleteConversionPipeline,
TestBatchConversion,
TestConversionWithDifferentParameters,
TestModelCompatibility
)
from test_error_handling import (
TestErrorHandling,
TestBoundaryConditions,
TestResourceLimitations,
TestConcurrencyAndThreadSafety
)
from test_performance import (
TestQuantizationPerformance,
TestModelSizeAndCompression,
TestConversionThroughput,
TestMemoryEfficiency
)
from test_all_quantization_types import TestAllQuantizationTypes
class NetransTestSuite:
"""Netrans测试套件管理器"""
def __init__(self):
# 使用绝对路径,避免工作目录改变后路径失效
self.test_dir = Path(__file__).parent.absolute()
# 直接使用test目录不再使用reports子目录
self.reporter = TestReporter(self.test_dir)
self.results = []
def create_test_suite(self, test_level: str = "all") -> unittest.TestSuite:
"""
创建测试套件
Args:
test_level: 测试级别 ('basic', 'full', 'performance', 'quantization', 'all')
"""
suite = unittest.TestSuite()
if test_level in ["basic", "all"]:
# 基础功能测试
suite.addTest(unittest.makeSuite(TestNetransCore))
suite.addTest(unittest.makeSuite(TestQuantizerTypes))
suite.addTest(unittest.makeSuite(TestModelMetadata))
if test_level in ["full", "all"]:
# 集成测试
suite.addTest(unittest.makeSuite(TestCompleteConversionPipeline))
suite.addTest(unittest.makeSuite(TestBatchConversion))
suite.addTest(unittest.makeSuite(TestConversionWithDifferentParameters))
# 错误处理测试
suite.addTest(unittest.makeSuite(TestErrorHandling))
suite.addTest(unittest.makeSuite(TestBoundaryConditions))
if test_level in ["performance", "all"]:
# 性能测试
suite.addTest(unittest.makeSuite(TestQuantizationPerformance))
suite.addTest(unittest.makeSuite(TestModelSizeAndCompression))
suite.addTest(unittest.makeSuite(TestConversionThroughput))
if test_level in ["quantization", "all"]:
# 全量化类型测试30种量化类型
suite.addTest(unittest.makeSuite(TestAllQuantizationTypes))
if test_level == "all":
# 高级测试(仅在完整测试时运行)
suite.addTest(unittest.makeSuite(TestModelCompatibility))
suite.addTest(unittest.makeSuite(TestResourceLimitations))
suite.addTest(unittest.makeSuite(TestConcurrencyAndThreadSafety))
suite.addTest(unittest.makeSuite(TestMemoryEfficiency))
return suite
def run_tests(self, test_level: str = "all", verbosity: int = 2) -> unittest.TestResult:
"""
运行测试套件
Args:
test_level: 测试级别
verbosity: 详细程度
"""
print(f"开始运行Netrans测试套件 (级别: {test_level})")
print("=" * 50)
suite = self.create_test_suite(test_level)
runner = unittest.TextTestRunner(
verbosity=verbosity,
stream=sys.stdout,
buffer=True
)
start_time = time.time()
result = runner.run(suite)
end_time = time.time()
# 生成测试摘要
self._generate_test_summary(result, end_time - start_time, test_level)
return result
def _generate_test_summary(self, result: unittest.TestResult,
execution_time: float, test_level: str):
"""生成测试摘要"""
print("\n" + "=" * 50)
print("测试执行摘要")
print("=" * 50)
total_tests = result.testsRun
failures = len(result.failures)
errors = len(result.errors)
skipped = len(result.skipped) if hasattr(result, 'skipped') else 0
passed = total_tests - failures - errors - skipped
print(f"测试级别: {test_level}")
print(f"总测试数: {total_tests}")
print(f"通过: {passed}")
print(f"失败: {failures}")
print(f"错误: {errors}")
print(f"跳过: {skipped}")
print(f"成功率: {(passed/total_tests*100):.1f}%" if total_tests > 0 else "0%")
print(f"执行时间: {execution_time:.2f}")
# 详细的失败和错误信息
if failures:
print("\n失败的测试:")
for test, traceback in result.failures:
print(f" - {test}: {traceback.split('AssertionError:')[-1].strip()}")
if errors:
print("\n错误的测试:")
for test, traceback in result.errors:
print(f" - {test}: {traceback.split('Exception:')[-1].strip()}")
# 生成JSON报告
summary_data = {
'test_level': test_level,
'execution_time': execution_time,
'total_tests': total_tests,
'passed': passed,
'failures': failures,
'errors': errors,
'skipped': skipped,
'success_rate': (passed/total_tests*100) if total_tests > 0 else 0,
'timestamp': time.strftime('%Y-%m-%d %H:%M:%S'),
'failed_tests': [str(test) for test, _ in result.failures],
'error_tests': [str(test) for test, _ in result.errors]
}
# 保存摘要到test目录
try:
import os
summary_file = self.test_dir / f"test_summary_{test_level}.json"
# 直接使用绝对路径写入,避免使用 Path.cwd() 和 .absolute()
# 因为 @chdir 装饰器可能导致当前工作目录被删除
with open(str(summary_file), 'w', encoding='utf-8') as f:
json.dump(summary_data, f, ensure_ascii=False, indent=2)
# 验证文件确实存在
if summary_file.exists():
file_size = summary_file.stat().st_size
print(f"\n✅ 详细报告已保存到: {summary_file}")
print(f"✅ 文件大小: {file_size} 字节")
else:
print(f"\n⚠️ 警告: 文件写入后找不到!")
except Exception as e:
print(f"\n❌ 错误: 无法保存测试报告")
print(f"异常类型: {type(e).__name__}")
print(f"异常信息: {e}")
import traceback
traceback.print_exc()
def main():
"""主函数"""
parser = argparse.ArgumentParser(description="Netrans AI模型转换工具测试套件")
parser.add_argument(
'--level',
choices=['basic', 'full', 'performance', 'quantization', 'all'],
default='basic',
help='测试级别: basic(核心功能), full(集成测试), performance(性能测试), quantization(全量化类型), all(所有测试) (默认: basic)'
)
parser.add_argument(
'--verbosity',
type=int,
choices=[0, 1, 2],
default=2,
help='输出详细程度 (0=最少, 1=正常, 2=详细)'
)
parser.add_argument(
'--list-tests',
action='store_true',
help='列出所有可用的测试'
)
parser.add_argument(
'--specific-test',
type=str,
help='运行特定的测试类 (例如: TestNetransCore)'
)
parser.add_argument(
'--timeout',
type=int,
default=None,
help='测试超时时间(秒)'
)
args = parser.parse_args()
# 创建测试套件管理器
test_suite = NetransTestSuite()
if args.list_tests:
# 列出所有测试
print("可用的测试类:")
test_classes = [
"TestNetransCore - 核心功能测试",
"TestQuantizerTypes - 量化器类型测试",
"TestModelMetadata - 模型元数据测试",
"TestCompleteConversionPipeline - 完整转换流程测试",
"TestBatchConversion - 批量转换测试",
"TestConversionWithDifferentParameters - 不同参数转换测试",
"TestModelCompatibility - 模型兼容性测试",
"TestErrorHandling - 错误处理测试",
"TestBoundaryConditions - 边界条件测试",
"TestResourceLimitations - 资源限制测试",
"TestConcurrencyAndThreadSafety - 并发和线程安全测试",
"TestQuantizationPerformance - 量化性能测试",
"TestModelSizeAndCompression - 模型压缩测试",
"TestConversionThroughput - 转换吞吐量测试",
"TestMemoryEfficiency - 内存效率测试",
"TestAllQuantizationTypes - 全量化类型测试 (30种量化类型) ⭐ 新增"
]
for test_class in test_classes:
print(f" {test_class}")
return
if args.specific_test:
# 运行特定测试
try:
# 动态导入测试类
test_module = sys.modules[__name__]
test_class = getattr(test_module, args.specific_test)
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(test_class))
runner = unittest.TextTestRunner(verbosity=args.verbosity)
result = runner.run(suite)
if result.wasSuccessful():
print(f"\n{args.specific_test} 测试通过")
sys.exit(0)
else:
print(f"\n{args.specific_test} 测试失败")
sys.exit(1)
except AttributeError:
print(f"错误: 未找到测试类 '{args.specific_test}'")
print("使用 --list-tests 查看可用的测试类")
sys.exit(1)
# 运行测试套件
try:
if args.timeout:
print(f"注意: 超时参数 {args.timeout} 秒已设置,但当前版本不支持强制超时。")
print("建议使用 Ctrl+C 手动停止过长的测试。\n")
result = test_suite.run_tests(
test_level=args.level,
verbosity=args.verbosity
)
# 根据测试结果设置退出码
if result.wasSuccessful():
print("\n✅ 所有测试通过!")
sys.exit(0)
else:
print("\n❌ 部分测试失败,请查看详细报告")
sys.exit(1)
except KeyboardInterrupt:
print("\n测试被用户中断")
sys.exit(1)
except Exception as e:
print(f"\n测试执行出现错误: {e}")
sys.exit(1)
if __name__ == '__main__':
main()