Unit Test fatalError in Swift

后端 未结 4 695
别跟我提以往
别跟我提以往 2020-12-08 02:24

How to implement unit test for a fatalError code path in Swift?

For example, I\'ve the following swift code

func divide(x: Float, by y:          


        
4条回答
  •  一整个雨季
    2020-12-08 03:11

    Swift 4 and Swift 3

    Based on Ken's answer.

    In your App Target add the following:

    import Foundation
    
    // overrides Swift global `fatalError`
    public func fatalError(_ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Never {
        FatalErrorUtil.fatalErrorClosure(message(), file, line)
        unreachable()
    }
    
    /// This is a `noreturn` function that pauses forever
    public func unreachable() -> Never {
        repeat {
            RunLoop.current.run()
        } while (true)
    }
    
    /// Utility functions that can replace and restore the `fatalError` global function.
    public struct FatalErrorUtil {
    
        // Called by the custom implementation of `fatalError`.
        static var fatalErrorClosure: (String, StaticString, UInt) -> Never = defaultFatalErrorClosure
    
        // backup of the original Swift `fatalError`
        private static let defaultFatalErrorClosure = { Swift.fatalError($0, file: $1, line: $2) }
    
        /// Replace the `fatalError` global function with something else.
        public static func replaceFatalError(closure: @escaping (String, StaticString, UInt) -> Never) {
            fatalErrorClosure = closure
        }
    
        /// Restore the `fatalError` global function back to the original Swift implementation
        public static func restoreFatalError() {
            fatalErrorClosure = defaultFatalErrorClosure
        }
    }
    

    In your test target add the following:

    import Foundation
    import XCTest
    
    extension XCTestCase {
        func expectFatalError(expectedMessage: String, testcase: @escaping () -> Void) {
    
            // arrange
            let expectation = self.expectation(description: "expectingFatalError")
            var assertionMessage: String? = nil
    
            // override fatalError. This will pause forever when fatalError is called.
            FatalErrorUtil.replaceFatalError { message, _, _ in
                assertionMessage = message
                expectation.fulfill()
                unreachable()
            }
    
            // act, perform on separate thead because a call to fatalError pauses forever
            DispatchQueue.global(qos: .userInitiated).async(execute: testcase)
    
            waitForExpectations(timeout: 0.1) { _ in
                // assert
                XCTAssertEqual(assertionMessage, expectedMessage)
    
                // clean up
                FatalErrorUtil.restoreFatalError()
            }
        }
    }
    

    Test case:

    class TestCase: XCTestCase {
        func testExpectPreconditionFailure() {
            expectFatalError(expectedMessage: "boom!") {
                doSomethingThatCallsFatalError()
            }
        }
    }
    

提交回复
热议问题