6
1

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のAttachmentでSwiftUIのスクリーンショットをUnit Testに残す

Last updated at Posted at 2025-12-17

はじめに

この記事はディップアドベントカレンダーの記事です。
WWDC2025の動画を見ていて、面白そうだと思って触ってみました!

Swift6.2のSwiftTesting

WWDC2025のWhat’s new in Swiftの動画でSwiftTestingのアップデートがちょこっと紹介されていました。

スクリーンショット 2025-12-18 0.00.43.png

毎日テストしますもんね。

この中でテスト失敗したときなどに、データを添付するAttachmentという機能が追加されていました。

AttachmentはSwiftTestingが提供するテスト結果にデータを添付するためのAPIとなっています。Attachmentで添付できるデータはAttachableに準拠している型で、画像・テキスト・Data などが扱えます。

テスト失敗のレポートがより詳細に表示できそうだったので使ってみようと思いました。

Attachment使ってみた

String型の添付

Attachment.record(_:named:) を使ってデータを添付させてみます。添付できるデータはString型、Json型などがあります。Attachableに準拠させていれば独自Data型でも使用することができます。

SwiftTestingTest.swift
    @Test("attachmentテスト")
    func counter_logic() async throws {
        let counter = Counter()
        counter.increment()
        #expect(counter.count == 1)
        Attachment.record("hogehoge", named: "test.txt")
    }

テスト結果を開き(command+6)JumpReportで詳細を確認します。

スクリーンショット 2025-12-18 0.34.23.png

テキストファイルが出力されました!🙌
スクリーンショット 2025-12-18 0.35.54.png

失敗時のみ添付

以下のように書くとテスト失敗時にデータを添付することもできます。

SwiftTestingTest.swift
    do {
        try #require(condition)
    } catch {
        Attachment.record("エラーです", named: "error.txt")
        throw error
    }

スクリーンショットを添付したい

テスト時の状態のスクリーンショットを添付することができればbuild確認の際に、楽になりそうなので実際にやってみました。

スクリーンショットを撮るための簡単なViewとロジックを用意します。(クリックしたらカウントアップ)

CounterView.swift
import SwiftUI

struct CounterView: View {
    let vm: CounterViewModel

    var body: some View {
        VStack(spacing: 12) {
            Text("count: \(vm.count)")
                .font(.title)

            Button("Increment") {
                vm.increment()
            }

            if vm.isOverLimit {
                Text("LIMIT!")
                    .font(.headline)
            }
        }
        .padding()
    }
}
CounterViewModel.swift
import Observation

@Observable
final class CounterViewModel {
    private(set) var count: Int = 0
    var isOverLimit: Bool { count >= 3 }

    func increment() {
        count += 1
    }
}

ImageRendererで画像へ

次にこのSwiftUIのViewを画像に変換する必要があります。今回はImageRendererを使用して、1つのUIImageとします。それをpngData()に変換して使用します。

ImageRenderer.swift
import SwiftUI
import Foundation

@MainActor
func renderPNGWithImageRenderer<V: View>(
    _ view: V,
    size: CGSize = CGSize(width: 393, height: 852),
    scale: CGFloat = 3
) -> Data? {
    let content = view
        .frame(width: size.width, height: size.height)
        .background(Color(.systemBackground))
        .environment(\.colorScheme, .light)

    let renderer = ImageRenderer(content: content)
    renderer.scale = scale

    return renderer.uiImage?.pngData()
}

背景色を設定していないと透明になるのでここでbackgroundColorを追加しています。
*サイズはiPhone準拠

テスト実行

これで準備は整いました!テストにAttachment.recordを追加してみましょう。

SwiftTestingTest.swift
@Test("Attach screenshot")
@MainActor
func counter_withAttachments() async throws {
    let vm = CounterViewModel()
    vm.increment()

    do {
        try #require(vm.count == 10) // わざとしっぱい
    } catch {
        if let png = renderPNGWithImageRenderer(CounterView(vm: vm)) {
            Attachment.record(png, named: "CounterView.png")
        }

        throw error
    }
}

テストが失敗するとその状態の画像が添付されました!👏

スクリーンショット 2025-12-18 1.03.43.png

最初に使ったString型のAttachmentを使えば他の情報もtext等で添付することもできます!

おわりに

ちょっこっと発表された内容でしたが、面白い使い方がたくさんありそうでSwiftTetingの幅が広がりました!
現状は画像を添付させただけですが、CIやスクリーンショットテストにも導入できるそうなので、今後やってみようと思います。
また、来年のWWDCではSwiftTestingのUITestやスクリーンショットテストができるようになるアップデートを待ちたいと思います😢

今回実行した環境:macOSTahoe26.1, Xcode 26.1, Swift6.2

6
1
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
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?