ASOへの取り組みで検索経由の訪問者が少しずつ増えてきたこともあり、「バグを出しにくくする仕組み」を見直したいと思い、これまで避けていたユニットテストにようやく手を出してみることにしました。
1. 何をテストすればいいのか分からず手が止まった
XCTestの書き方自体はドキュメントを読めば理解できたのですが、いざ自分のコードに対してテストを書こうとすると、何をテストすべきなのか判断がつかず手が止まりました。
func testExample() {
// 何をassertすればいいのか分からない
}
最初は「全部テストしなければ」という完璧主義に陥りかけたのですが、まずは「計算やデータ変換のように、入力に対して出力が一意に決まる処理」から手をつけると決めてから、迷いなく書き進められるようになりました。
2. UIに依存したコードはテストが書けないと気づいた
いざ既存のコードにテストを追加しようとすると、ビジネスロジックと画面の更新処理が同じ関数の中に混在していて、テストしにくいことに気づきました。
// テストしづらい: UIの更新とロジックが混ざっている
func calculateTotal() {
let total = items.reduce(0) { $0 + $1.price }
totalLabel.text = "\(total)円" // UIへの依存
}
計算部分だけを独立した関数に切り出し、UIの更新は呼び出し側に任せる形に整理してから、ようやくテストが書けるようになりました。テストを書こうとしたことで、それまで気づいていなかった設計の甘さに向き合うことになりました。
// テストしやすい: ロジックだけを独立させる
func calculateTotal(items: [Item]) -> Int {
items.reduce(0) { $0 + $1.price }
}
3. given-when-thenの型を知ってテストが書きやすくなった
テストのコードをどう構成すればいいのか迷っていたのですが、「given(準備)・when(実行)・then(検証)」という型に沿って書くと整理しやすいと知りました。
func testCalculateTotal() {
// given: 準備の部分
let items = sampleItems()
// when: 実行の部分
let total = calculateTotal(items: items)
// then: 検証の部分
XCTAssertEqual(total, 300)
}
自由に書いていた頃は「このテストは結局何を確認しているのか」が後から読み返すと分かりにくかったのですが、この型に沿ってからは、自分自身が読み返したときにも意図がすぐに追えるようになりました。
4. テストがあることで、直したはずのバグが実感を持って安心できた
SwiftDataのスキーマ変更のときのように、以前は1つの修正が別の箇所を壊していないか、毎回手動で画面を触って確認していました。テストを書いた計算処理については、修正後にテストを走らせるだけで壊れていないことが確認できるようになり、「多分大丈夫」ではなく「テストが通っているから大丈夫」と言える安心感を初めて実感しました。
まとめ
- 最初から全部テストしようとせず、入力と出力が一意に決まる処理から始めるとよい
- ビジネスロジックとUIの更新が混在しているコードはテストが書きにくい。ロジックを独立させる設計の見直しにつながる
- 「given-when-then」の型に沿って書くと、テストの意図が後から見ても分かりやすくなる
- テストがあることで、修正の安全性を「感覚」ではなく「確認できる事実」として持てるようになる
すべてのコードをテストで覆うにはまだ程遠いですが、小さく始めたことで、テストの効果を実感として持てたのは大きな収穫でした。
次は、NavigationStackへの移行でハマった話をまとめます。
本記事は生成AI(Claude)を活用して執筆・編集しています。内容は実体験に基づき、執筆者本人が確認・監修しています。


コメント