#!/usr/bin/env python3 """测试入口:跑全部测试,然后按 unittest 的判定结果退出。 为什么需要这一层(而不是直接 ``python -m unittest discover -s tests``): **QtWebEngine 在 offscreen 下的解释器退出路径会崩**(Windows 实测:测试全绿、 进程却以段错误结束,退出码 139)。CI 只看退出码,于是绿色测试被判成失败; 而且崩在哪一步与用例数量有关,非常难缠。测试的成败本来就该由 unittest 的 ``result`` 决定,所以拿到结果后立刻 ``os._exit``,绕开那段我们控制不了的 C++/解释器清理路径。 注意这**不掩盖真实崩溃**:测试跑到一半崩(进程真的挂了)时,unittest 根本 拿不到结果,退出码照样非 0。 用法:: python tests/run_tests.py # 全部 python tests/run_tests.py -p "test_client_*" # 只跑一部分(同 discover 的 -p) python tests/run_tests.py -v # 逐条打印 """ import argparse import os import sys import unittest TESTS_DIR = os.path.dirname(os.path.abspath(__file__)) def main(argv=None): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("-p", "--pattern", default="test_*.py", help="测试文件匹配(同 unittest discover 的 -p)") parser.add_argument("-v", "--verbose", action="store_true", help="逐条打印") parser.add_argument("-f", "--failfast", action="store_true", help="第一个失败就停") args = parser.parse_args(argv) # 从测试目录里发现:helpers.py 与测试模块都按"平铺导入"写(见 helpers) sys.path.insert(0, TESTS_DIR) os.chdir(TESTS_DIR) suite = unittest.TestLoader().discover(TESTS_DIR, pattern=args.pattern) runner = unittest.TextTestRunner(verbosity=2 if args.verbose else 1, failfast=args.failfast) result = runner.run(suite) passed = result.wasSuccessful() summary = ("全部通过" if passed else f"失败 {len(result.failures)} / 错误 {len(result.errors)}") sys.stdout.write(f"{summary}\n") sys.stdout.flush() sys.stderr.flush() # 立刻退出:不要让解释器去跑那段会崩的 Qt/Chromium 清理 os._exit(0 if passed else 1) if __name__ == "__main__": main()