web-dev-qa-db-ja.com

Swiftでスロー機能を単体テストする方法は?

Swift 2.0の関数がスローされるかどうかをテストする方法は?正しいErrorTypeがスローされることをアサートする方法は?

35
Fabio Poloni

編集:Swift 4.1のコードを更新しました。

最新のSwift Fyodor Volchyokの答え)のバージョンXCTAssertThrowsErrorを使用したユーザー:

    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 enumに値が関連付けられている場合、Error enumを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
        }
    }
60
Ferschae Naej

少なくともXcode 7.3(おそらくそれ以前)では、組み込みのXCTAssertThrowsError()を使用できます。

_    XCTAssertThrowsError(try methodThatThrows())
_

テスト中に何もスローされない場合、次のようなものが表示されます。

enter image description here

スローされたエラーが具体的なタイプであるかどうかを確認したい場合は、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)
    }
_
18
Fyodor Volchyok

次の関数と宣言がある場合:

_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_-ステートメントで行います。これは他の言語と比較して最良の方法ではありません。

あなたはあなたが...

  • return内のcatchは正しい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")
}
_
10
Fabio Poloni

Swift 4.1関連する値のテストを投げるエラー

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."))
    }
}
1
Declan McKenna

この機能を使用できます:

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)
0