XCTest测试运行器启动后未执行测试求助(Vapor+Python依赖)
问题:Vapor XCTest环境中测试无法执行,进程超时终止
我正在用Vapor(搭配XCTVapor)和Python作为应用依赖搭建XCTest环境,但测试完全没执行。5分钟后进程终止,提示:Test runner never began executing tests after launching
应用入口代码:
static func main() async throws { var env = try Environment.detect() try LoggingSystem.bootstrap(from: &env) guard let stdLibPath = Bundle.main.path(forResource: "python-stdlib", ofType: nil) else { return } guard let libDynloadPath = Bundle.main.path(forResource: "python-stdlib/lib-dynload", ofType: nil) else { return } setenv("PYTHONHOME", stdLibPath, 1) setenv("PYTHONPATH", "\(stdLibPath):\(libDynloadPath)", 1) // Temporarily disable Python Py_Initialize() print ("Py_Initialize complete") // we now have a Python interpreter ready to be used let app = Application(env) defer { app.shutdown() } do { try await configure(app) } catch { app.logger.report(error: error) throw error } try await app.execute() }
我能在app.execute()处触发断点,但后续无进展,测试用例断点从未触发,通过XCode构建。
调度线程spindump信息:
Thread 0x23a87 DispatchQueue "com.apple.main-thread"(1) 412 samples (1-412) priority 46 (base 46) 412 start + 1903 (dyld + 25631) [0x7ff80675441f] 412 main + 102 (entrypoint.swift in app + 14630) [0x1050d4926] 412 ??? (libswift_Concurrency.dylib + 227060) [0x7ffc0beb16f4] 412 ??? (libswift_Concurrency.dylib + 227107) [0x7ffc0beb1723] 412 CFRunLoopRun + 40 (CoreFoundation + 1041893) [0x7ff806c0b5e5] 412 CFRunLoopRunSpecific + 560 (CoreFoundation + 503489) [0x7ff806b87ec1] 412 __CFRunLoopRun + 1365 (CoreFoundation + 506496) [0x7ff806b88a80] 412 __CFRunLoopServiceMachPort + 145 (CoreFoundation + 511999) [0x7ff806b89fff] 412 mach_msg + 19 (libsystem_kernel.dylib + 6282) [0x7ff806a6f88a] 412 mach_msg_overwrite + 692 (libsystem_kernel.dylib + 34260) [0x7ff806a765d4] 412 mach_msg2_trap + 10 (libsystem_kernel.dylib + 5538) [0x7ff806a6f5a2] *411 ipc_mqueue_receive_continue + 0 (kernel + 1528192) [0xffffff8000451180] *1 ipc_mqueue_receive_continue + 0 (kernel + 1528192) [0xffffff8000451180]
其他线程均来自NIO线程池(NIO-ELT-和TP-#),各16个线程。
测试文件代码:
@testable import app //import XCTVapor import PythonKit //import XCTest import XCTVapor final class appTests: XCTestCase { override func setUp() async throws { try await super.setUp() } override func setUpWithError() throws { print ("setupWthError 1") try super.setUpWithError() print ("setupWthError 2") } func testPython() async throws { print("TestPython") let sys = Python.import("sys") XCTAssertNotNil(sys) print("Python Version: \(sys.version_info.major).\(sys.version_info.minor)") print("Python Encoding: \(sys.getdefaultencoding().upper())") print("Python Path: \(sys.path)") _ = Python.import("math") // verifies `lib-dynload` is found and signed successfully } func testHelloWorld() async throws { let app = Application(.testing) defer { app.shutdown() } try await configure(app) try app.test(.GET, "hello", afterResponse: { res in XCTAssertEqual(res.status, .ok) XCTAssertEqual(res.body.string, "Hello, world!") }) } }
解决方案
1. 解除主线程阻塞(核心问题)
app.execute()会启动Vapor应用并持续监听请求,直接占用主线程陷入CFRunLoop循环,导致XCTest runner根本无法拿到主线程执行测试逻辑。修改入口代码,仅在非测试环境下启动服务:
static func main() async throws { var env = try Environment.detect() try LoggingSystem.bootstrap(from: &env) // 测试环境下直接返回,不启动服务 guard env != .testing else { return } guard let stdLibPath = Bundle.main.path(forResource: "python-stdlib", ofType: nil) else { return } guard let libDynloadPath = Bundle.main.path(forResource: "python-stdlib/lib-dynload", ofType: nil) else { return } setenv("PYTHONHOME", stdLibPath, 1) setenv("PYTHONPATH", "\(stdLibPath):\(libDynloadPath)", 1) Py_Initialize() print ("Py_Initialize complete") let app = Application(env) defer { app.shutdown() } do { try await configure(app) } catch { app.logger.report(error: error) throw error } try await app.execute() }
2. 调整Python初始化逻辑
全局初始化Python可能干扰测试环境,建议将初始化逻辑移到单个测试用例内部,避免影响整个测试进程:
func testPython() async throws { print("TestPython") // 测试内部初始化Python,用完销毁 guard let stdLibPath = Bundle.main.path(forResource: "python-stdlib", ofType: nil) else { XCTFail("找不到Python标准库") return } guard let libDynloadPath = Bundle.main.path(forResource: "python-stdlib/lib-dynload", ofType: nil) else { XCTFail("找不到Python动态库目录") return } setenv("PYTHONHOME", stdLibPath, 1) setenv("PYTHONPATH", "\(stdLibPath):\(libDynloadPath)", 1) Py_Initialize() defer { Py_Finalize() } let sys = Python.import("sys") XCTAssertNotNil(sys) print("Python Version: \(sys.version_info.major).\(sys.version_info.minor)") print("Python Encoding: \(sys.getdefaultencoding().upper())") print("Python Path: \(sys.path)") _ = Python.import("math") }
3. 修复测试依赖导入
测试文件中注释掉了import XCTest,虽然XCTVapor可能间接导入,但明确导入能避免潜在问题:
import XCTest
内容的提问来源于stack exchange,提问作者nishant
相关产品推荐
相关产品推荐

