[TDD][SwiftUI] SwiftUI と TDD で作る ボーリングスコアアプリ(その3 スコア計算 モデルの追加実装)

ボーリングアプリ(スコアを記録するアプリ)を、SwiftUI と TDD で作ってみます。
[TDD][SwiftUI] SwiftUI と TDD で作る ボーリングスコアアプリ(その1 モデル作成 Part1) [TDD][SwiftUI] SwiftUI と TDD で作る ボーリングスコアアプリ(その2 View と ViewModelの作成 Part1)

どんなモデルとビューを作ったかは、上記記事を参照ください。

アプリ設計:振り返り

ここまでに、MVVM の基本的なところを実装し、以下ができるようになっています。

  • ボーリングスコア風の表示
  • 1〜10フレームのスコア記録

初期の設計で困るところは発生していませんので、このまま実装していきます。

今回は、「スコア計算」です。

アプリ設計:追加設計

スペアとストライクの扱いはまだ着手せずに進めていきます。

つまり、スコア計算は、それまでの各投球でのピン数を合計すれば良いことになります。

ただし、以下を決定しておかないといけません。

  • 投球が完了していないフレームでの合計スコア表示

1投しただけの状態で、その1投目までの合計を表示すべきか、2投目が終わるまで、”-” 表示で良いかを決める必要があります。

ここでは、2投目が終わるまでは(スペア、ストライクを考慮した時には、必要な情報が集められるようになるまでは)、スコア表示しないこととして、代わりに”-” を表示することとしました。

MEMO
少し調べたのですが、どのように表示するのが正式なのかわかりませんでした。

もしかするとボーリングのルールとしては、途中での計算は決めていないのかもしれません。

スコア計算もチェックするテスト

前回のテストを改良して、第1フレームの2投を入力後にスコア表示をチェックするように修正しましょう。

まずは、テストでチェックできるように Accessibility ID を付与する必要があります。

ここでは、FrameScoreView0 〜 FrameScoreView9 という ID を付与するようにしています。

FrameScoreView に accessibility ID 付与

以下は、2投した状態で、チェックするテストです。
1投目は1ピン、2投目は5ピン倒した結果を入力として、表示内容をチェックしています。

test_RecordOneFrame_TwoBowl_ShouldBeRecordedAndAtFirstFrame

setupWithError 内の、continueAfterFailure を = true とすると、Assert が Failure しても最後までテストを実行するようになります。

そうすることで、各投球の表示は期待通りになっていて、スコア表示のテストで Failure していることがわかります。

ここまでのスコア計算の実装状況

Model ではなにも実装していません。以下のように、ViewModel が、”0″ を返しているという実装です。ですので、初期状態でも、テストが Failure しています。

現在のスコア計算@ViewModel

ここでは、ViewModel が計算するのではなく、Model に問い合わせて結果を View に渡すという実装にします。

スコア計算の実装

BowlingGame へ実装

モデル (BowlingGame) へスコア計算を実装していきます。

スペア・ストライクを考慮しないのであれば、フレーム分の2投後でのスコアは、
「前のフレームまでのスコア+2投で倒したピン数」となります。

また、関数返り値を Int? として、まだ計算するための情報が揃っていない時には、nil を返す仕様とします。

スコア計算@BowlingGame

ViewModel は、Model の計算結果を使って、View に返すように実装を修正します。

スコア計算@BowlingGameViewModel

先ほどの1フレームのテストは、うまく Pass します。

シミュレータでの実行は、以下のようになります。

スコア計算実装その1

「スコア計算実装その1」

スペア・ストライクをチェックしていないので、入力された数字の合計がスコアになっています。

いまは、1フレームしかテストしていませんので、(スペア・ストライクでない)10フレームまでの入力で、スコアが正しいことを確認するテストを追加しましょう。

Refactoring

テストを追加する前に、将来的なテストに対しての準備を兼ねて、すこし Refactoring しておきましょう。

ボタンとテキストは、常に参照すると思いますので、Setup で取得して、配列で保持しておくことにします。

テキストが存在するかを確認するテストも別途作成しました。(test_LabelExists)

ボタンをテキストを事前に取得しておくことで、これまでのテスト test_RecordOneFrame_TwoBowl_ShouldBeRecordedAndAtFirstFrame は、シンプルになりました。

TDDBowlingUITests refactoring

テストの追加

Refactoring して、コードが見易くなり、追加もしやすくなりましたので、10フレームまでの新しいテストを追加して、確認することにします。

テスト用のユーティリティ関数も追加しました。前回のテストは、1行になっています。

example code

シミュレータで動作させると、どんどんスコアが追加されていくのが見えて、面白いです。

まとめ その3

10フレームまで記録できるようにはなりました。

次に、スペア・ストライクの表示対応とスコア計算対応と進めていく予定です。

説明は以上です。次回に続きます。Happy Coding!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です