如何在
Swift中执行fatalError代码路径的单元测试?
例如,我有以下swift代码
func divide(x: Float,by y: Float) -> Float { guard y != 0 else { fatalError("Zero division") } return x / y }
当y = 0时,我想单位测试的情况.
注意,我想使用fatalError不是任何其他断言功能.
这个想法是用自己的内置fatalError函数替换,在单元测试的执行期间被替换,以便您在其中运行单元测试断言.
然而,棘手的部分是fatalError是@noreturn,所以你需要用一个永远不会返回的函数来覆盖它.
覆盖fatalError
仅在您的应用程序目标中(不要添加到单元测试目标):
// overrides Swift global `fatalError` @noreturn func fatalError(@autoclosure message: () -> String = "",file: StaticString = __FILE__,line: UInt = __LINE__) { FatalErrorUtil.fatalErrorClosure(message(),file,line) unreachable() } /// This is a `noreturn` function that pauses forever @noreturn func unreachable() { repeat { NSRunLoop.currentRunLoop().run() } while (true) } /// Utility functions that can replace and restore the `fatalError` global function. struct FatalErrorUtil { // Called by the custom implementation of `fatalError`. static var fatalErrorClosure: (String,StaticString,UInt) -> () = 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. static func replaceFatalError(closure: (String,UInt) -> ()) { fatalErrorClosure = closure } /// Restore the `fatalError` global function back to the original Swift implementation static func restoreFatalError() { fatalErrorClosure = defaultFatalErrorClosure } }
延期
将以下扩展名添加到您的单元测试目标:
extension XCTestCase { func expectFatalError(expectedMessage: String,testcase: () -> Void) { // arrange let expectation = expectationWithDescription("expectingFatalError") var assertionMessage: String? = nil // override fatalError. This will pause forever when fatalError is called. FatalErrorUtil.replaceFatalError { message,_,_ in assertionMessage = message expectation.fulfill() } // act,perform on separate thead because a call to fatalError pauses forever dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED,0),testcase) waitForExpectationsWithTimeout(0.1) { _ in // assert XCTAssertEqual(assertionMessage,expectedMessage) // clean up FatalErrorUtil.restoreFatalError() } } }
测试用例
class TestCase: XCTestCase { func testExpectPreconditionFailure() { expectFatalError("boom!") { doSomethingThatCallsFatalError() } } }
我从这篇文章中得到了关于单元测试断言和前提条件的想法:
Testing assertion in Swift