ViewModelのテスト
プレゼンテーションロジックを単体でテストします。
「ViewModelのテスト」はCoddyKit上の無料Swift Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSwift Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Swift Academyコースには全4レッスンが含まれています。
ViewModelをテストする理由
ViewModelはプレゼンテーションロジックを保持するため、単体テストを行う価値が最も高い層です。UIKitやSwiftUIに依存しないため、単独で高速かつ決定論的にテストできます。
テストしやすい設計
適切に構築されたViewModelは、初期化子を通して依存関係を受け取ります。これにより、テストでフェイクに置き換えられます。
final class WeatherViewModel: ObservableObject {
@Published var temperatureText = ""
private let service: WeatherService
init(service: WeatherService) {
self.service = service
}
}依存性の注入
具体的な依存関係をプロトコルの背後に隠します。ViewModelは抽象化に依存するため、テストではモックを注入できます。
protocol WeatherService {
func fetchTemperature() async throws -> Double
}モックを作成する
モックはプロトコルに準拠し、あらかじめ用意したデータを返します。ViewModelが受け取る内容を正確に制御できます。
final class MockWeatherService: WeatherService {
var stubbedTemperature: Double = 20
var didCallFetch = false
func fetchTemperature() async throws -> Double {
didCallFetch = true
return stubbedTemperature
}
}基本的な単体テスト
モックを注入したら、ViewModelがデータを正しく変換することをアサートします。
func testFormatsTemperature() async {
let mock = MockWeatherService()
mock.stubbedTemperature = 25
let vm = WeatherViewModel(service: mock)
await vm.load()
XCTAssertEqual(vm.temperatureText, "25 C")
}状態遷移をテストする
ViewModelは状態を表すenumを公開することがよくあります。その状態を生成する入力を与えて、各分岐をテストします。
func testLoadingThenLoaded() async {
let vm = FeedViewModel(service: MockFeedService())
XCTAssertEqual(vm.state, .loading)
await vm.load()
XCTAssertEqual(vm.state, .loaded(["A", "B"]))
}エラー経路をテストする
モックでエラーをスローし、ViewModelが失敗を適切に処理してエラー状態を公開することを確認します。
final class FailingService: WeatherService {
func fetchTemperature() async throws -> Double {
throw URLError(.notConnectedToInternet)
}
}
func testShowsErrorOnFailure() async {
let vm = WeatherViewModel(service: FailingService())
await vm.load()
XCTAssertEqual(vm.state, .error)
}インタラクションを検証する
結果だけでなく、依存関係が呼び出されたことを確認したい場合もあります。モックにスパイ用のフラグを持たせると、動作をアサートできます。
func testFetchIsCalled() async {
let mock = MockWeatherService()
let vm = WeatherViewModel(service: mock)
await vm.load()
XCTAssertTrue(mock.didCallFetch)
}@Publishedの出力をテストする
Combineを使って@Publishedプロパティを購読し、発行された値を取得して、その順序をアサートできます。
var received: [String] = []
let cancellable = vm.$temperatureText.sink { received.append($0) }
await vm.load()
XCTAssertEqual(received.last, "25 C")
cancellable.cancel()テストを高速に保つ
モックは即座に値を返し、実際のネットワークも使用しないため、ViewModelのテストは数ミリ秒で実行できます。実際のタイマーやURLSessionは避け、クロックやスケジューラにもフェイクを注入します。
ベストプラクティス
効果的なViewModelテストのポイントは次のとおりです。
- すべての依存関係をプロトコル経由で注入する
- 1つのテストメソッドで1つの動作をテストする
- 成功、空、エラーの経路を網羅する
- ビューが読み取る公開出力をアサートする
理解度チェック
ViewModelのテストについての知識を確認しましょう。
まとめ
ViewModelを単独で単体テストする方法を学びました。
- プロトコルの背後にある依存関係を注入する
- モックで入力を制御し、呼び出しをスパイする
- 成功、エラー、空の状態を網羅する
@Publishedの出力と状態遷移をアサートする
テストしやすいViewModelは、MVVMの関心の分離によって得られる成果です。
よくある質問
「ViewModelのテスト」レッスンは無料ですか?
はい。「ViewModelのテスト」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Swift Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Swift Academyコースには全4レッスンが含まれています。
「ViewModelのテスト」で何を学びますか?
プレゼンテーションロジックを単体でテストします。 ブラウザで直接実行するハンズオンコードでSwift Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Swift Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのSwift Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「ViewModelのテスト」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このSwift Academyレッスンでコードを書いて実行できますか?
はい。すべてのSwift Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- MVVMパターン
- ViewModelとViewのバインディング
- Coordinatorパターン
- ViewModelのテスト