You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止Xcode在fatalError/preconditionFailure时自动断点?

How to Test fatalError/preconditionFailure with a Test Host in Xcode

I totally get your frustration—when running tests with a Test Host, Xcode’s debugger automatically breaks on these fatal runtime checks, halting your test suite before you can verify the trigger logic. Here’s how to fix this, with two reliable approaches:

Approach 1: Wrap Fatal Calls in Configurable Closures (Best Practice)

The cleanest way is to decouple your framework from direct calls to fatalError/preconditionFailure, making them replaceable for testing.

Step 1: Update Your Framework Code

Create helper structs to wrap these fatal functions:

// In your framework
public struct RuntimeErrorHandler {
    // Wrap fatalError
    public static var fatalError: (@autoclosure () -> String, StaticString, UInt) -> Never = Swift.fatalError
    
    // Wrap preconditionFailure
    public static var preconditionFailure: (@autoclosure () -> String, StaticString, UInt) -> Never = Swift.preconditionFailure
}

Then replace all direct calls to fatalError/preconditionFailure in your framework with the wrapped versions:

// Instead of fatalError("Invalid input")
RuntimeErrorHandler.fatalError("Invalid input", #file, #line)

// Instead of preconditionFailure("State invalid")
RuntimeErrorHandler.preconditionFailure("State invalid", #file, #line)

Step 2: Override the Closures in Tests

In your test class, replace the closures to track triggers instead of crashing:

@testable import YourFramework

class FrameworkValidationTests: XCTestCase {
    private var didTriggerFatal = false
    private var capturedFatalMessage = ""
    private var didTriggerPrecondition = false
    private var capturedPreconditionMessage = ""

    override func setUp() {
        super.setUp()
        
        // Override fatalError to track instead of crash
        RuntimeErrorHandler.fatalError = { [weak self] message, _, _ in
            self?.didTriggerFatal = true
            self?.capturedFatalMessage = message()
            XCTFail("Fatal error was triggered: \(message())")
            Thread.exit() // Exit the test thread without killing the entire suite
        }
        
        // Override preconditionFailure similarly
        RuntimeErrorHandler.preconditionFailure = { [weak self] message, _, _ in
            self?.didTriggerPrecondition = true
            self?.capturedPreconditionMessage = message()
            XCTFail("Precondition failure was triggered: \(message())")
            Thread.exit()
        }
    }

    override func tearDown() {
        // Restore original implementations
        RuntimeErrorHandler.fatalError = Swift.fatalError
        RuntimeErrorHandler.preconditionFailure = Swift.preconditionFailure
        
        // Reset tracking flags
        didTriggerFatal = false
        capturedFatalMessage = ""
        didTriggerPrecondition = false
        capturedPreconditionMessage = ""
        
        super.tearDown()
    }

    // Example test for fatalError trigger
    func testInvalidInputTriggersFatalError() {
        // Call the framework method that should trigger fatalError
        try? frameworkMethodWithInvalidInput()
        
        // Verify the trigger
        XCTAssertTrue(didTriggerFatal)
        XCTAssertEqual(capturedFatalMessage, "Invalid input")
    }

    // Example test for preconditionFailure trigger
    func testInvalidStateTriggersPreconditionFailure() {
        frameworkMethodWithInvalidState()
        
        XCTAssertTrue(didTriggerPrecondition)
        XCTAssertEqual(capturedPreconditionMessage, "State invalid")
    }
}

Approach 2: Disable Exceptions Breakpoint for Tests

If you don’t want to modify your framework code, you can adjust Xcode’s breakpoint behavior to skip breaking on fatal errors during tests:

  1. Open the Breakpoint Navigator (⌘+8).
  2. Right-click the All Exceptions breakpoint and select Edit Breakpoint.
  3. In the Condition field, paste this:
    !(BOOL)[[NSProcessInfo processInfo].environment objectForKey:@"XCTestConfigurationFilePath"]
    
  4. Click Done.

This condition tells Xcode to skip the exception breakpoint when running tests (since the XCTestConfigurationFilePath environment variable is only present during test execution). Note this is a global setting, so it will apply to all your test targets.


内容的提问来源于stack exchange,提问作者Gligor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:11:15