【问题标题】:How to unit test throwing functions in Swift?如何在 Swift 中对投掷函数进行单元测试?
【发布时间】:2015-09-30 07:30:54
【问题描述】:

如何测试 Swift 2.0 中的函数是否抛出异常?如何断言抛出了正确的ErrorType

【问题讨论】:

    标签: xcode swift unit-testing


    【解决方案1】:

    编辑:更新了Swift 4.1 的代码(对Swift 5.2 仍然有效)

    这是使用XCTAssertThrowsErrorFyodor Volchyok's answer的最新Swift版本:

        enum MyError: Error {
            case someExpectedError
            case someUnexpectedError
        }
    
        func functionThatThrows() throws {
            throw MyError.someExpectedError
        }
    
        func testFunctionThatThrows() {
            XCTAssertThrowsError(try functionThatThrows()) { error in
                XCTAssertEqual(error as! MyError, MyError.someExpectedError)
            }
        }
    

    如果您的Error 枚举具有关联值,您可以让您的Error 枚举符合Equatable,或使用if case 语句:

        enum MyError: Error, Equatable {
            case someExpectedError
            case someUnexpectedError
            case associatedValueError(value: Int)
        }
    
        func functionThatThrows() throws {
            throw MyError.associatedValueError(value: 10)
        }
    
        // Equatable pattern: simplest solution if you have a simple associated value that can be tested inside 1 XCTAssertEqual
        func testFunctionThatThrows() {
            XCTAssertThrowsError(try functionThatThrows()) { error in
                XCTAssertEqual(error as! MyError, MyError.associatedValueError(value: 10))
            }
        }
    
        // if case pattern: useful if you have one or more associated values more or less complex (struct, classes...)
        func testFunctionThatThrows() {
            XCTAssertThrowsError(try functionThatThrows()) { error in
                guard case MyError.associatedValueError(let value) = error else {
                    return XCTFail()
                }
    
                XCTAssertEqual(value, 10)
                // if you have several values or if they require more complex tests, you can do it here
            }
        }
    

    【讨论】:

    • 对于 Swift 4.1,Equatable 是自动合成的,因此我们只需将协议放入,我们的关联值就可以直接在 XCTAssertEqual 中进行比较。
    【解决方案2】:

    至少在 Xcode 7.3(可能更早)中,您可以使用内置的XCTAssertThrowsError()

    XCTAssertThrowsError(try methodThatThrows())
    

    如果在测试过程中没有抛出任何东西,您会看到如下内容:

    如果你想检查抛出的错误是否是某种具体类型,你可以使用XCTAssertThrowsError()errorHandler参数:

    enum Error: ErrorType {
        case SomeExpectedError
        case SomeUnexpectedError
    }
    
    func functionThatThrows() throws {
        throw Error.SomeExpectedError
    }
    
    XCTAssertThrowsError(try functionThatThrows(), "some message") { (error) in
        XCTAssertEqual(error as? Error, Error.SomeExpectedError)
    }
    

    【讨论】:

      【解决方案3】:

      给定以下函数和声明:

      enum SomeError: ErrorType {
          case FifthError
          case FirstError
      }
      
      func throwingFunction(x: Int) throws {
          switch x {
          case 1:
              throw SomeError.FirstError
          case 5:
              throw SomeError.FifthError
          default:
              return
          }
      }
      

      如果给函数赋予 5,则该函数将抛出 FifthError,如果给定 1,则抛出 FirstError

      为了测试,一个函数成功运行单元测试可能如下所示:

      func testNotError() {
          guard let _ = try? throwingFunction(2) else {
              XCTFail("Error thrown")
              return
          }
      }
      

      let _ 也可以替换为任何其他名称,因此您可以进一步测试输出。

      要断言函数抛出,无论ErrorType 是什么,单元测试可能如下所示:

      func testError() {
          if let _ = try? throwingFunction(5) {
              XCTFail("No error thrown")
              return
          }
      }
      

      如果您想测试特定的ErrorType,可以使用do-catch-statement 完成。与其他语言相比,这不是最好的方法。

      你必须确保你...

      • returncatch 中为正确的ErrorType
      • XCTFail()return 用于所有其他 catch
      • XCTFail() 如果没有 catch 被执行

      鉴于此要求,测试用例可能如下所示:

      func testFifthError() {
          do {
              try throwingFunction(5)
          } catch SomeError.FifthError {
              return
          } catch {
              XCTFail("Wrong error thrown")
              return
          }
          XCTFail("No error thrown")
      }
      

      【讨论】:

      • 我相信按照 Fyodor Volchyok 的建议使用 XCTAssertThrowsError 方法会更有意义。
      【解决方案4】:

      Swift 4.1 Error throwing Test for associated values

      enum ParseError: Error, Equatable {
          case unexpectedArgument(String)
      }
      
      func testWithNoSchemaButWithOneArgument() {
          XCTAssertThrowsError(try Args(withSchema: "", andArguments: ["-x"])) { error in
              XCTAssertEqual(error as? ParseError, ParseError.unexpectedArgument("Argument(s) -x unexpected."))
          }
      }
      

      【讨论】:

        【解决方案5】:

        你可以使用这个功能:

        func XCTAssertThrowsError<T, E: Error & Equatable>(
          _ expression: @autoclosure () throws -> T,
          error: E,
          in file: StaticString = #file,
          line: UInt = #line
          ) {
          var thrownError: Error?
          XCTAssertThrowsError(
            try expression(),
            file: file,
            line: line) {
              thrownError = $0
          }
        
          XCTAssertTrue(
            thrownError is E,
            "Unexpected error type: \(type(of: thrownError))",
            file: file,
            line: line
          )
        
          XCTAssertEqual(
            thrownError as? E,
            error,
            file: file,
            line: line
          )
        }
        

        例子:

        XCTAssertThrowsError(try funcThatThrowsSpecificError(), error: SpecificErrorEnum.someError)
        
        猜你喜欢
        • 2014-11-07
        • 1970-01-01
        • 2014-02-08
        • 2021-08-02
        • 1970-01-01
        • 2019-04-15
        • 1970-01-01
        • 2013-05-22
        • 1970-01-01
        相关资源
        最近更新 更多