0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Swift Testing で値を監視する

Last updated at Posted at 2025-05-14

Swift Testingで値を監視したい

と書いたが、別にXCTestでも、テストでなくてもなんでも良い。
値を非同期で監視し続ける場合に値が更新されたのを待って、テストを走らせたいということがある。
例えば以下のようなViewModelがあったとして、personに値が入ってからテストケースを実行したいとする。
SwiftTesting内にこの値を監視するメソッドがないわけではないが使いにくかったので自作した。

@MainActor
@Observable
final class ViewModel {
    var person: Person?

    init() {
        observe()
    }

    func observe() {
        Task { [weak self] in
            let stream: AsyncStream<Person> = ...
            for await value in stream {
                guard let self else { return }
                person = value
            }
        }
    }
}

ちなみにTaskを用いる場合weak selfは必要ないとよく言われるが、AsyncStreamの場合は必須である(別にweak selfでなくても良いがこのTaskを抜ける処理がないと永遠とメモリ上に存在してしまう)。

自作したメソッドは以下

func observe(content: @Sendable @escaping () async -> Bool, maxAttemtpts: Int = 10) async throws {
  let timer = AsyncStream { try? await Task.sleep(for: .seconds(0.5)) }
  var count: Int = 0
  for await value in timer {
    if await content() { return }
    count += 1
    if count >= maxAttemtpts { throw TestObserverError() }
  }
}

struct TestObserverError: Error {}

これをテスト内で以下のように用いる

import Testing
@Test("Test")
func test() async throws {
    let state = ViewModel()
    try await observe() { await state.person != nil }
    ... いろいろなテスト
}

以上
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?