📝

XCTContext.runActivity で "Current context must not be nil" と言われたときの対処法

2023/03/26に公開

XCTContext.runActivity はメソッドにしなくても処理をグループにまとめることができて大変便利だけど、例えば async なテストメソッドで XCTContext.runActivity を実行するとクラッシュして使えないのでそれの対処法。

環境

Xcode 14.1

先に結論

XCTContext.runActivity はメインスレッドで実行しろ。

事象

async なテストメソッドで XCTContext.runActivity を使うとクラッシュする。

final class SandboxTests: XCTestCase {
    func testAsync() async throws {
        XCTContext.runActivity(named: "これは失敗する") { _ in
            XCTAssertTrue(true)
        }
    }
}

なお下記のように DispatchQueue.global で囲ってもクラッシュする。

func testGlobalQueue() {
    DispatchQueue.global().async {
        XCTContext.runActivity(named: "これも失敗する") { _ in
            XCTAssertTrue(true)
        }
    }
}

解決法

詳しい原因はわかりませんが、どうやらメインスレッド以外だとクラッシュするようです。
なので明示的にメインスレッドで実行するようにすると発生しなくなります。

// async メソッドなら @MainActor にする
@MainActor
func testAsync() async throws {
    XCTContext.runActivity(named: "これは成功する") { _ in
        XCTAssertTrue(true)
    }
}

// DispatchQueue なら、 DispatchQueue.main.async 内で実行するようにする
func testGlobalQueue() {
    DispatchQueue.global().async {
        DispatchQueue.main.async {
            XCTContext.runActivity(named: "これも成功する") { _ in
                XCTAssertTrue(true)
            }
        }
    }
}

メインスレッド以外、 XCTContext の Context(?) が nil になるのかな・・・?

余談

上記のような事象が発生したり、入れ子にした XCTContext で await するとレポートで見たときに入れ子が解除されてたりするので async メソッドで XCTContext.runActivity を使うのは厳しいなーという所感でした。

今後のアップデートに期待!

Discussion