stream-swift-test-helpers

Stream iOS SDK 用于测试目的的测试助手。使用 Swift 编写。

先决条件

为了使用这个 Swift Package,你需要:

安装指南

  1. 在 Xcode 11(及以上版本)的偏好设置-账户下设置你的 GitHub 账户

  2. 将此仓库添加到你的 Xcode 项目:https://github.com/GetStream/stream-swift-test-helpers.git

  3. StreamSwiftTestHelpers 包作为 Swift Package Dependency 添加到你项目的测试目标。

  4. 正确添加后,你应该在项目导航器窗格中的 Swift Package dependencies 下看到它

  5. 通过在你的测试文件中导入它们来开始使用 StreamSwiftTestHelpersimport StreamSwiftTestHelpers,或者 @_exported import StreamSwiftTestHelpers 来使其可用于整个目标。


第三方依赖项

此软件包依赖于 Difference Swift 软件包,该软件包提供了一种更好的方法来识别两个实例之间的差异。 TestHelpers

此软件包还依赖于 SnapshotTesting Swift 软件包,该软件包允许创建快照测试。

用法

StreamSwiftTestHelpers - 单元测试

测试 Result 类型

// Success value
XCTAssertEqual(result, success: "Success Value")
XCTAssertResultSuccess(result)

// Failure
XCTAssertEqual(result, failure: MyError.first)
XCTAssertResultFailure(result)

以类型安全的方式测试错误

XCTAssertEqual(MyError.first, .first)

XCTAssertThrowsError(try PathUpdate(with: data), ParsingError.failedToParseJSON)

测试 Swift 中的错误

重要的是不要将错误视为代码中的异类,而是将它们作为 API 的第一公民。 在 Swift 中测试错误在很多情况下是一个繁琐的过程,测试助手旨在提高你的生产力。


它是如何工作的

Swift 中的通用错误可以基于它们的反射进行比较

public extension Error {
    var stringReflection: String {
        return String(reflecting: self)
    }
}

测试错误的相等性

假设我们声明了一个带有这个 case 的 enum

public enum DeliveryStatusError: Error, Hashable {
  ...
  case fileSendingIsDisabled(messageId: String?)
  ...
}

我们可以利用 XCTAssertEqual 现在包含一个测试 API 的事实,该 API 允许我们测试两个错误的相等性。 如果可以推断出给定错误的类型,我们可以利用类型安全,它会免费附带代码补全!

  XCTAssertEqual(error, .fileSendingIsDisabled(messageId: "some-long-id"))

抛出示例

与其编写像这样的代码

func testItThrowsAnInternalError() {
    // given
    let myStruct = MyStruct()

    // when
    XCTAssertThrowsError(try myStruct.runningThisFuncCanThrow(), "It should throw error") { (error) in
        // then
        switch error {
        case let error as MyError:
            switch error {
            case .internalError:
                XCTAssertTrue(true)
            default:
                XCTFail("It didnt throw an internalError error")
            }
        default:
            XCTFail("It didnt throw MyError, error: \(error)")
        }
    }
}

你可以使用助手 XCTAssertThrowsTypedError

func testItThrowsTypedInternalError() {
    // given
    let myStruct = MyStruct()

    // then
    XCTAssertThrowsError(try myStruct.runningThisFuncCanThrow(),
                         MyError.internalError,
                         "It should throw error")
}

在 Swift 中测试 Result

由于 Result 本质上是一个 enum,因此测试 Result 类型通常需要你切换其 case 以识别该结果的成功/失败 case。 如果你经常使用 Result 类型,这可能会成为负担。

与其编写像这样的测试

func testRequestingTheResourceGivesMeSuccessResult() {
    // given
    let myStruct = MyStruct()

    // when
    let result = myStruct.requestSuccessResource()

    // then
    switch result {
    case .success:
        XCTAssertTrue(true)
    case .failure:
        XCTFail("The result is failure")
    }
}

测试成功的 Result

你可以像这样测试 Result 的成功

func testSuccessResult() {
    // given
    let myStruct = MyStruct()

    // when
    let result = myStruct.requestSuccessResource()

    // then
    XCTAssertResultSuccess(result)
    XCTAssertEqual(result, success: "Succes value")
}

此测试将断言结果是否为 failure

测试失败的 Result

使用给定错误类型测试失败结果看起来像这样

func testFailureResult() {
    // given
    let myStruct = MyStruct()

    // when
    let result = myStruct.requestFailureResource()

    // then
    XCTAssertResultFailure(result)
    XCTAssertEqual(result, failure: MyError.internalError)
}

StreamSwiftTestHelpers - UI 测试

此包提供了编写 UI 测试、访问 UI 元素以及在其上运行操作和手势的支持。

Robot 模式

此包允许你围绕两个基本概念构建 UI 测试架构 - Robot 模式和 GIVEN、WHEN、THEN、AND 表示法。

将 UI 测试实现细节隐藏在 `Robot 之后。

public protocol Robot: AnyObject {}

你可能需要创建尽可能多的 Robot,以便在 UI 测试套件运行期间与你的应用程序进行交互。

示例

func testReceiveMessage() throws {
    let message = "test message"
    let author = "Han Solo"

    GIVEN("user opens the channel") {
        userRobot.login().openChannel()
    }
    WHEN("participant sends the message: '\(message)'") {
        participantRobot
            .startTyping()
            .stopTyping()
            .sendMessage(message)
    }
    THEN("the message is delivered") {
        userRobot
            .waitForParticipantsMessage()
            .assertMessageAuthor(author)
    }
}