Как проверить метод, который вызывает ошибку в Swift 2?

Это мое определение метода:

func isValidForMode(mode: DBFindViewControllerMode) throws -> Bool { }

Теперь я могу проверить это простым способом, так как я знаю, что он НЕ делает выдает ошибку:

XCTAssertTrue(try! searchOptionsManager.isValidForMode(.Address))

Но что, если я знаю, что метод выбрасывает?

Лучшим решением будет XCTAssertThrows(), но это не: -)

Ниже моя попытка:

do {
    try searchOptionsManager.isValidForMode(.Address)
} catch let error {
    XCTAssertEqual(error as! DBErrorType, DBErrorType.CannotBeEmpty("Street"))
}

Но он терпит неудачу, потому что:

Невозможно найти перегрузку для XCTAssertEqual, которая принимает список аргументов типа (DBErrorType, DBErrorType)

Ответ 1

Сделайте свой DBError в соответствии с Equatable:

enum DBError: ErrorType, Equatable {
  case CannotBeEmpty(message: String)
}

func ==(lhs: DBError, rhs: DBError) -> Bool {
  switch (lhs, rhs) {
    case (.CannotBeEmpty(let leftMessage), .CannotBeEmpty(let rightMessage)):
      return leftMessage == rightMessage
  }
}

И затем вы можете использовать его в XCTAssertEqual:

func testExample() {
  do {
    try isValid()
  }
  catch let e as DBError {
    XCTAssertEqual(e, DBError.CannotBeEmpty(message: "Street"))
  }
  catch {
    XCTFail("Wrong error")
  }
}

Или создайте свой собственный XCTAssertThrows.

enum DBError: ErrorType, Equatable {
  case CannotBeEmpty(message: String)
}

func ==(lhs: DBError, rhs: DBError) -> Bool {
  switch (lhs, rhs) {
    case (.CannotBeEmpty(let leftMessage), .CannotBeEmpty(let rightMessage)):
      return leftMessage == rightMessage
  }
}

и

func XCTAssertThrows<T: ErrorType where T: Equatable>(error: T, block: () throws -> ()) {
  do {
    try block()
  }
  catch let e as T {
    XCTAssertEqual(e, error)
  }
  catch {
    XCTFail("Wrong error")
  }
}

class TestsTests: XCTestCase {

    func testExample() {
      XCTAssertThrows(DBError.CannotBeEmpty(message: "Street")) { try isValid() }
    }

}

Ответ 2

Или просто используйте необязательный try:

extension XCTestCase {
    func XCTAssertThrows(@autoclosure expression: () throws -> Void, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) {
        XCTAssert((try? expression()) == nil, message, file: file, line: line)
    }
}

Не нужно соответствовать Equatable

Ответ 3

Лучшее решение, которое я нашел, это:

do {
    try searchOptionsManager.isValidForMode(.Address)
    XCTAssertTrue(false)
} catch {
    XCTAssertTrue(true)
}

Таким образом, вы можете проверить, действительно ли выбрано исключение, но вы не можете проверить, какой тип исключений вызывается.

Ответ 4

Вот ответ @robertvojta с несколькими модификациями для Xcode 9 и Swift 3 - 4:

extension XCTestCase {
    func XCTAssertThrows<ErrorType: Error, T>(expression: @autoclosure () throws -> T, error: ErrorType) where ErrorType: Equatable {
        do {
            _ = try expression()
        } catch let caughtError as ErrorType {
            XCTAssertEqual(caughtError, error)
        } catch {
            XCTFail("Wrong error")
        }
    }
}

Использование:

enum APIError: LocalizedError {
    case cancelled

    public var errorDescription: String? {
        switch self {
        case .cancelled:
            return "The operation has been cancelled by user."
        }
    }
}

func testThatIsThrowsCancelledByUserError() {
    XCTAssertThrows(expression: try api.cancelLoginOperation(), error: APIError.cancelled)
}

Ответ 5

Если вы знаете, что функция выдает ошибку, вы также должны убедиться, что вы терпите неудачу в случае, если ошибка не была выбрана.

Я изменяю ответы от @robertvojta и @vadim-bulavin здесь:

extension XCTestCase {
    func XCTAssertThrows<ErrorType: Error, T>(expression: @autoclosure () throws -> T, error: ErrorType) where ErrorType: Equatable {
        do {
            _ = try expression()
            XCTFail("No error thrown")
        } catch let caughtError as ErrorType {
            XCTAssertEqual(caughtError, error)
        } catch {
            XCTFail("Wrong error")
        }
    }
}

Использование:

enum APIError: LocalizedError {
    case cancelled

    public var errorDescription: String? {
        switch self {
        case .cancelled:
            return "The operation has been cancelled by user."
        }
    }
}

func testThatIsThrowsCancelledByUserError() {
    XCTAssertThrows(expression: try api.cancelLoginOperation(), error: APIError.cancelled)
}

Ответ 6

Вот пример, который вы поймете при попытке проверить этот ниже код

func validateCredencials() throws {

guard username.characters.count > 0  && password.characters.count > 0 
else { throw EncryptionType.Empty }
    guard password.characters.count >= 5 else { throw EncryptionType.Short }
}
    do {
    try validateCredencials()
    }catch EncryptionType.Empty {
        print("password Empty")

    } catch EncryptionType.Short {
        print("Password too shoot")
    }catch {
        print("Some thing went Wrong")
    }

Надеюсь, вы понимаете