Alice 3: 测试

在开始各种操作符之前,我们先来聊聊测试。

规范

Swift Package Manager 的规范是约定大于配置,在这个规范里,测试非常简单。

先在 Package.swift 里加一个新的 test target:AsyncTests

targets: [
    .target(name: "Async", dependencies: []),
    .testTarget(name: "AsyncTests", dependencies: ["Async"])
]

再创建对应的文件夹 /Tests/AsyncTests

可以愉快地写测试啦!

XCTest

Apple 为开发者们提供了 XCTest 来写单元测试。

XCTest 的设计简单,易用。不过如果你的项目需要复杂测试的话,我推荐使用 Quick + Nimble,它有着更丰富的断言系统以及更强大的组织系统,可以帮你写出有着高可读性和高表现力的测试代码。

框架的选择要从需求出发,在目力所及的地方 XCTest 都够用,所以我选择 XCTest 作为测试框架。我在 CombineX 里大量使用 Quick & Nimble,对它们有兴趣的可以参考~

XCTest 的使用非常简单,定义你的继承自 XCTestCase 的类,写以 test 开头的方法即可。

比如我们要测试 Future

class FutureTests: XCTestCase {
    
    func testComplete() {
        var count = 0
        let p1 = Promise<Bool, Never>()
        
        p1.future.whenSucceed { _ in
            count += 1
        }
        p1.succeed(true)
        
        XCTAssertEqual(count, 1)
        
        let p2 = Promise<Bool, Error>()
        p2.future.whenFail { _ in
            count += 1
        }
        p2.fail(TestError.e1)
        
        XCTAssertEqual(count, 2)
    }
}

XCTest 就是使用如 XCAssertEqual(a, b) 这样的断言来进行测试的。

除了 XCAssertEqual 外,常用的还有:

如果你想要等待一个异步任务的完成并测试,需要使用 expectation

func testDelay() {
    let e = expectation(description: "testDelay")
    
    let p = Promise<Int, Never>()
    
    var ed: Date?
    p.future.delay(0.1, on: .main).whenSucceed { _ in
        ed = Date()
        XCTAssertTrue(Thread.isMainThread)
        e.fulfill()
    }
    
    let sd = Date()
    p.succeed(1)
    
    waitForExpectations(timeout: 0.2, handler: nil)
    
    XCTAssertNotNil(ed)
    XCTAssertGreaterThan(ed!.timeIntervalSince(sd), 0.1)
}

就是这样!

Linux

测试方法都使用 test 开头是为了让 XCTest 发现这些用例。

但在 linux 上,XCTest 是无法这样发现用例的。我们想让 Alice 也支持 linux,所以需要做一些额外的工作。

首先,在每个测试类里定义一个静态变量,它是一个元组数组,其中元祖的第一个值是描述用例的字符串,第二个值是用例方法的名字。

class FutureTests {
    static var allTests = [
        ("testPending", testPending),
        ("testInspect", testInspect),
        ("testComplete", testComplete),
        ("testObservers", testObservers)
    ]
}

接着,在每个 test target 里加一个 XCTestManifests.swift 文件,它的内容就是暴漏所有测试类的 allTests 变量。

import XCTest

#if !canImport(ObjectiveC)
public func allTests() -> [XCTestCaseEntry] {
    return [
        testCase(FutureTests.allTests),
        testCase(OperatorsTests.allTests)
    ]
}
#endif

最后,在 /Tests 目录下加一个 LinuxMain 文件,内容如下:

import XCTest

import AsyncTests

var tests = [XCTestCaseEntry]()
tests += AsyncTests.allTests()
XCTMain(tests)

搞定啦!

让我们在 travis 上加一个 matrix,让 ci 在 linux 上也跑一下吧!

新的 .travis.yml 如下:

branches:
  only:
    - master

matrix:
  include:
    - os: linux
      language: generic
      dist: xenial
      env: SWIFT_VERSION="5.1"
      sudo: required
    - os: osx
      language: swift
      osx_image: xcode11.1

before_install:
  - if [[ $TRAVIS_OS_NAME == 'linux' ]]; then
      eval "$(curl -sL https://raw.githubusercontent.com/kylef/swiftenv/master/docs/install.sh)";
    fi

script: 
  - swift test

要记得在 linux 上先安装 swift 哦。

求交流,求 star——

你的反馈就是对我最大的鼓励。


#swift #http #future #alice #alice-serial

Comments