単体テストが簡単になるようにゲームのソフトウェアを設計する方法は?


25

ゲーム開発の状況でJUnitのようなテストフレームワークを使用することは実用的ですか?ゲームをよりテストしやすくするために、どのような設計上の考慮事項に従うことができますか?ゲームのどの部分をテストできる/すべきであり、どの部分を人間のテストに委ねるべきである/すべきですか?

たとえば、ゲームループが1つの関数にカプセル化されている場合、テストするのは非常に難しいようです。私は、時間の差分をとり、ゲームロジックを進める「更新」機能をリファクタリングするのが好きです。これにより、偽のより遅い時間差を与えることでゲームを遅くする機能など、いくつかの興味深いトリックが可能になります。


6
プレイテストを行うために事実上無限の奴隷労働者の軍隊があるのに、ユニットテストを書く工数を無駄にするのはなぜですか?私は子供、私は子供...;)
マイクストロベル

1
実際、あなたは子供である必要はありません、それは本当に良い点です!私はそれについては考えていませんでしたが、ゲームは他の人にテストしてもらうのに最も簡単なタイプのソフトウェアです。自動化されたゲームテスト(ユニットまたはその他)の難しさをいくらか相殺していると思います。
リケット

3
単体テストは、必ずしもアプリケーションが全体として正しく動作することを確認することではありません(つまり、機能テスト)。将来の変更が既存の機能を壊さないようにすることです。確かに、ユーザーは宇宙船が上下逆さまになっていることを確認できますが、パスアルゴリズムが.001オフになっていると、ゲームが200時間プレイされるまで効果が現れない場合があります。これは、コードがドアから出る前に単体テストでキャッチできるものです。
ウェイドウィリアムズ

1
ゲームはユーザーがプレイするのに最も簡単なソフトウェアですが、プレイすることテストです!適切なバグレポートを取得するのは非常に困難です。さらに、コード内のバグの発生箇所を追跡し、新しい変更が既存のコードを破壊しないことを確認することは、自動テストの劇的なメリットをもたらします。
正式な

回答:


25

TDDの原則の1つは、TDDがデザインに影響を与える場合があるということです。システムのテストを作成し、そのテストに合格するコードを作成して、依存関係をできるだけ浅くします。

私にとって、単体テストの一部としてテストしていないことは2つだけです。

第一に、視覚的な要素や物の見た目をテストしません。私はそれをテストし、更新後にオブジェクトが正しい場所にあること、カメラが境界の外側のオブジェクトをカリングすること、変換(少なくともシェーダーの外部で行われるもの)がグラフィックエンジンに引き渡される前に適切に実行されることをテストします、しかし、それがグラフィックシステムに到達したら、線を引きます。DirectXのようなものを模倣しようとするのは好きではありません。

第二に、メインのゲームループ機能を実際にテストしていません。妥当なデルタを渡されたときにすべてのシステムが動作し、必要なときにシステムが正しく連携することをテストします。次に、ゲームループ内の正しいデルタで各システムを更新します。実際には、各システムが正しいデルタで呼び出されたことを示すテストを行うこともできますが、多くの場合、その過剰を見つけます(デルタを取得するための複雑なロジックを実行していなければ、過剰ではありません)。


6
最初の段落が重要です。事実、TDDでは、テストを許可するためだけに、コードを設計するよりもコードを設計する必要があります。彼らはデザインの専門家であるが、もちろん、ほとんど自分のスキルに感銘を受けたものは...通常、学ぶことがほとんどでものであることを当然多くのシンクタンクの
ダッシュ-トム・バン

2
その結果、コードが必ずしもより良く設計されていることに同意しません。テスト可能な依存関係を注入するために、以前はクリーンだったインターフェイスを開いてカプセル化を解除しなければならなかった、多くの嫌悪感を見てきました。
キロタン

4
私は、テストが既存のクラスのために書かれている場合に、他の方法よりも起こることがわかります。
ジェフ

@Kylotanは、おそらく不適切な設計/不十分なテスト設計の症状です。モックをリファクタリングし、クリーンなテストを行うために使用します。コードをより悪い状態にハッキングしないでください。それは起こるはずのことの反対です。
ティモックスリー

2
カプセル化は良いことですが、なぜ重要なのかを理解することが重要です。依存関係と大きないインターフェイスを隠すためだけに使用する場合、内部の設計がおそらくあまり良くないという負荷を大いに叫ぶでしょう。カプセル化は、主に見苦しいコードと依存関係を隠すことではなく、コードを理解しやすくすることと、消費者がコードについて推論しようとする際に辿るパスを少なくすることを主な目的としています。
マーティンオデリウス

19

Noel Llopisは、あなたが探していると思う程度に単体テストをカバーしています。

ゲームループ全体のテストに関しては、コードの機能の低下を防ぐ別の手法があります。アイデアは、リプレイシステムを介してゲームをプレイすることです(つまり、プレーヤーの入力を最初に記録し、それから別の実行でリプレイします)。再生中に、各フレームの各オブジェクトの状態のスナップショットを生成します。この状態のコレクションは、「ゴールデンイメージ」と呼ばれます。コードをリファクタリングするとき、リプレイを再度実行し、各フレームの状態をゴールデンイメージの状態と比較します。異なる場合、テストは失敗しています。

この手法の利点は明らかですが、次の点に注意する必要があります。

  • ゲームは決定論的である必要があるため、システムクロック、システム/ネットワークイベント、決定論的にシードされていない乱数ジェネレーターなどに注意する必要があります。等
  • ゴールデンイメージが生成された後にコンテンツが変更されると、ゴールデンイメージとの正当な違いが生じる可能性があります。これを回避する方法はありません。コンテンツを変更する場合、ゴールデンイメージを再生成する必要があります。

+1また、このアプローチの価値は「黄金のイメージ」の長さに直接関係していることも注目に値します。長さが足りないと、バグを簡単に見逃してしまいます。それが長すぎる場合、あなたは多くのことを待つことになります。このモードでは、通常の実行時環境よりも1桁高速にゲームを実行して、時間を節約することが重要です。レンダリングをスキップすると役立ちます!
エンジニア

9

私は、Jeffとjpaverの両方のコメントに同意します。また、アーキテクチャにコンポーネントモデルを採用すると、テスト容易性が大幅に向上することを付け加えました。コンポーネントモデルでは、各コンポーネントは単一の作業単位を実行し、単独で(またはモックオブジェクトが制限されている状態で)テスト可能である必要があります。

同様に、エンティティに依存するゲームの他の部分は、機能するコンポーネントのサブセットのみに依存する必要があります。実際には、これは通常、これらの領域のテストを容易にするためにいくつかの偽のコンポーネントをモックアウトできること、または単にテスト目的で部分エンティティを構成できることを意味します。たとえば、レンダリングおよび入力コンポーネントは物理をテストするために必要ないため、除外します。

最後に、ゲームコミュニティの一部のインターフェイスから得たパフォーマンスに関するアドバイスは無視します。インターフェイスを使用してコードを適切に記述し、将来的にパフォーマンスの問題が発生した場合、問題を解決するために簡単にプロファイル、識別、およびリファクタリングを行うことができます。インターフェイスのパフォーマンスへの影響や、追加された複雑さのオーバーヘッドに関するNoelの懸念に納得しませんでした。

とは言うものの、あらゆる小さなことを個別にテストしようとして、行き過ぎないでください。ほとんどのことと同様に、テストと設計は適切なバランスをとることに関するものです。


SXに慣れていないように見えますが、回答は順序付けられておらず、「上記の両方のコメント」のようなものはすぐに非推奨になることに注意してください。この時点で他の2つの答えのうち。:)
リケット

ありがとう、私はコメントしながらそれについて考えなかった。それ以来、個々のコメントを抽出するためにコメントを更新しました。
アレックスSchearer

3

OPのコメントに応答して、ユーザーが単体テストを置き換えることができるという2番目の回答を追加すると思いました。ユニットテストの目的は品質を保証することではないため、これは完全に間違っていると思います。プログラムの品質を保証するためのテストが必要な場合は、シナリオテストを調査するか、優れた監視に投資する必要があります。

(優れた監視とサービスとして実行されている製品では、実際に顧客に「テスト」をプッシュすることができますが、エラーを迅速に検出し、責任のある変更をロールバックする高度なシステムが必要です。小さな開発チーム。)

単体テストの主な利点は、開発者がより適切に設計されたコードを書くことを強制することです。テストという行為により、開発者は懸念を分離し、データをカプセル化する必要があります。また、開発者がインターフェイスやその他の抽象化を使用して、1つのことだけをテストするように勧めています。


同意しますが、単体テストは開発者に良いコードを書くことを強制しません。別のオプションがあります:非常にひどく書かれたテスト。コーダーのユニットテストのアイデアへのコミットメントが必要です。
tenpn

2
もちろん、お風呂の水で赤ちゃんを捨てる理由はありません。責任を持ってツールを使用しますが、最初にツールを使用します。
アレックスSchearer
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.