ひとりでゲームを作っている場合、仕様はわりところころ変わるものだと思います。
仕様をころころ変えられるのが個人で作っている醍醐味でもありますし、「正しさ」ではなく「面白さ」の方が大事なゲームというジャンルにおいては、最初に考えた仕様にこだわるのはあまり意味がないのでは、とも思います。
「正しい仕様」というものがない以上、テストは書けない、となりそうな気がするんですが、そして実際テストコードをほとんど書いてないんですが、実際のところどうなんでしょうか。
「ゲームにテストコードは不要!」と決めつけることなく、どういう部分ならテストコードを適用できそうかを、過去に書いたコードを見ながら振り返ってみたいと思います。そして次の開発に活かそうかと。
『ピクセルニンジャ』というゲームを作りました。忍者を操作して進んでいくアクションゲームです。ブラウザでお手軽に遊べるのでよかったらどうぞ。
今回はこのゲームを対象にテストコードは書けたのかどうかを考えてみたいと思います。
『ピクセルニンジャ』は、ざっくり、
という構成で書かれていますが、今回は、どんなツールを使って書いているのかには依存しない部分を考えたいと思います。
外部ライブラリは外部ライブラリを作ってる人がテストしているのでテストコード不要となります。
とはいえ、実際には外部ライブラリに不具合があるケースもなくはないので、意図しない現象が発生した場合は手動であれこれ試すケースはありました。
ほとんどの場合は「ライブラリの使い方が間違っていた」となりますが、本当にライブラリ側がバグってるケースもあり、そういうときは GitHub 上でそのバグについてのやりとりがあったりします。そのやりとりを見て、
の判断をしますが、このへんは全部手動での作業になるので、今回の「テストコードを書いてテストを自動化する」という話とは違うため「テストコードは不要」となります。
長々書いてしまいましたが、テストコードを使わないケースの例として挙げてみました。
本当はテストコードを書きたいケースなんですが、プログラムの中で音が鳴っているかどうか、を外部から判断する方法がないので、結局人間が耳で聴くしかない、となります。
また、iPhone の場合そもそもユーザーが画面をタッチしないと音が鳴らない仕様のため、手動テスト以外に方法がありません。
音声ファイルに限らず、画像ファイル等のリソース系ファイルが一定時間内に読み込めているかどうかについてはテストコードを書いたほうがいいんじゃないかと思いました。人間が気が付きづらい部分になるし、「n 秒以上になったらエラー」というのは仕様として明確なため。
「n 秒以上になったらエラー」だとブラウザを立ち上げてのテストになって若干面倒なので、単純に「リソースファイルの合計サイズが n 以上になったらエラー」とだけ書いてもいいかもしれません。このテストなら簡単に書けるので。
Aseprite というドット絵描画ツールがあり、Aseprite にはスライス情報などのデータを JSON として出力する機能があります。
そしてその JSON データを読み取り、スライス情報を返すような関数群を自作しています。
この部分は他のゲームでも汎用的に使える部分なので、テストコードを書く意味があると思います。
についてはテストコードを書ける、書いたほうがよさそう、ということになるかと思います。
今回は書いていないので、次にゲームを作るときに書いてみようかと。
画面の見た目が意図した通りになっているかどうかをテストする方法はあるものの、じゃあそれをゲームの画面に適用すべきかどうかは微妙なところです。
「ゲームの見た目や UI の配置を変える」というのは、ゲーム制作をする上で本当に頻繁に行う作業になるため、そのたびにテストコードを変えるのは効率が悪すぎるんじゃないかと思います。人間の目によるチェックが必ず入る部分でもありますし。
「画面上部に置かれるナビゲーションバー部分」なんかは、複数のゲームの使われる部分になるのでテストコードを書いてもいいかもしれませんが、この部分でデグレを起こしたケースが今のところないので、書くコストが見合わないかなと思っています。
ということで、現状では画面の見た目についてはテストコードを書かなくてもいいかなと思っています。「共通コンポーネント部分でデグレが発生し、その修正にかなりの時間を使った」というケースが発生したらテストコードの追加を検討しようかと。
「ゲーム開始ボタンをクリックしたらモードが『プレイモード』に変わる」とかはテストを自動化できる部分になると思います。
ただ、これも画面の見た目ほどではないもののそこそこ試行錯誤する部分になるので、テストコードを書けるようになるのはゲームが完成に近づいたあたりから、ということになるんですよね。
そしてわりと根本的なことですが「ゲームは一度作ったらあんまり機能追加しない」という特徴があるんですよね。これがゲームに対してテストコードを書く意味が薄い一番の理由かもしれません。
ただ、最近は一本のゲームを数年に渡って作り上げていく、みたいなスタイルも結構あるので、そういう場合は入力系のテストコードを書く意味は十分あると思います。
フレームレートが落ちていないかどうかはゲーム作成中にしょっちゅう確認する部分であり、また「フレームレートが特定の数値より下になったらエラー」は仕様として明確かつ、どのゲームにも当てはまる仕様なので、これについてはテストコードを書く意味があると思います。
ただ、ブラウザを立ち上げた上で実際にゲームを動かす必要があるので、テストコードを書くのは結構大変かなと思います。書く意味はあるんだけど、書くコストが見合うかどうか、という感じですね。ゲーム一本作るのと同じくらい大変な気が。
「プレイヤーのライフが 0 になったらゲームオーバーモードに変わる」とかはテストコードを書けると思うんですが、ただこれはゲームごとにロジックが変わる部分になるので、書くメリットは薄いかなと。
複数のゲームで以下のような関数を使いまわしています。
このへんはメジャーな外部ライブラリではなく、ネットで拾ったコードを使っているので、自前でテストコードを書く意味はあると思います。
ただ、この文章を書いていて「外部ライブラリに差し替えたほうが良いのでは?」とも思ったので、テストコードを書く労力があったらメジャーな(ちゃんとテストされてそうな)外部ライブラリを探したほうがいいかもしれません。
これも自動化できる部分になりますね。人間の耳だとチェックが難しい部分でもあるし。
テストコードを書くというよりは、音量を一定以下に調整してくれるツールを探したほうがいいと思いますが、なんにしても自動化したほうがいい部分かと思います。
最初にイメージした通り、個人制作のゲームについてはテストを自動化できる部分が少ない、という結論になりそうですが、以下の部分は自動化する意味がありそうだなという気付きも得られたので、振り返った意味は一応あったんじゃないかと思います。
あとは、一般的な話ですが、「コードをテスト可能な形に切り出す」というのは大事だなと思いましたね。まずはそこを見分けるところからやっていきたいと思います。