弾の当たり判定を直した。動くようになった。ところが後で気づくと、扉が開かなくなっている。触ってもいないはずの場所が壊れています。
機能が10個あるゲームでは、1つ直すたびに10個を手で確認しないと安心できません。20個になれば20個です。この繰り返しを機械にやらせる仕組みが 自動テスト で、UEには標準で入っています。この記事では、Blueprintだけで書ける Functional Test を作り、走らせ、わざと赤くしてから直すところまでを扱います。
この記事でわかること
- 手で確認することの限界
- UEのテストは 2種類(Blueprint勢は Functional Test から)
Functional Testを親にした Blueprintを作るAssert系ノードでの 判定の書き方- Session Frontend で走らせる
- 実践: HPが100→80になることをテストにし、一度赤くする
手で確認する限界
小さな試作なら、手で確認するほうが速いです。機能が3つなら3つ触るだけです。
問題は、機能の数と確認の手間が掛け算になることです。

| 機能の数 | 1つ直したときに確認すべき数 | 現実 |
|---|---|---|
| 3 | 3 | 手でやれる |
| 10 | 10 | だんだん省き始める |
| 20 | 20 | もう全部は見ない |
そして省いたところが壊れます。「触っていないから大丈夫」と思った場所が、共有している変数や共通の親クラス経由で影響を受けているからです。
自動テストの価値は、 「壊れていないことを、毎回タダで確認できる」 ことです。1度書けば、何回でも走らせられます。
この記事集では「わざと壊して直す」実践を何度もやってきました。 その裏返しが自動テストです。壊れていないことを、毎回確認する側の道具です。
UEのテストは2種類
UEには2種類のテストがあります。どちらから入るかで難易度が大きく変わります。

| 種類 | 何をするか | 向いているもの | 必要なもの |
|---|---|---|---|
| Functional Test | テスト用レベルにActorを置き、実際に動かして結果を判定 | ゲームプレイの検証(弾が当たる、扉が開く) | Blueprintだけ |
| C++のテスト | 関数単位で検証する | 計算ロジック(ダメージ計算式など) | C++ |
Blueprintだけで作っているなら、Functional Test から入るのが正解です。
Functional Testは、UEらしい独特な形をしています。テストそのものがレベルに置くActorなのです。
- テスト用のレベルを1つ作る
- そこに、テスト用のActor(Functional Testを親にしたBlueprint)を置く
- そのActorが自分でゲームを操作して、結果を判定する
「テストコードを書く」というより、 「テスト用のステージを作る」 感覚に近いです。ゲームを作る作業とほとんど同じなので、Blueprintに慣れているなら入りやすいはずです。
最初のFunctional Test
作り方は3ステップです。

- テスト用レベルを作る(
L_Test_Damageなど)。テスト専用なので、床とライトだけの最小構成で構いません - Blueprintを作る。親クラスに
Functional Testを指定します(クラス一覧で「すべてのクラス」から検索) - そのBlueprintをテスト用レベルに置く
Functional Testを親にすると、専用のイベントが使えるようになります。
| イベント / ノード | 役割 |
|---|---|
| Event Start Test | テストの開始。ここから検証を書く |
| Finish Test | テストの終了。成功か失敗を渡す |
| Assert 系 | 期待値と比べる(次の節) |
大事なのは、Finish Test を必ず呼ぶことです。呼ばないとテストは終わらず、タイムアウトで失敗扱いになります。
Finish Test の Test Result に渡す値で結果が決まります。
Succeeded— 成功Failed— 失敗Invalid— 前提が満たされずテストにならなかった
判定の書き方
検証の中身は Assert 系のノードで書きます。「期待値と実際の値が一致するか」を確かめるノードです。
| ノード | 確かめること |
|---|---|
| Assert True | 条件が true か |
| Assert False | 条件が false か |
| Assert Equal (Int) | 整数が期待値と一致するか |
| Assert Equal (Float) | 小数が期待値と一致するか(許容誤差を指定できる) |
| Assert Is Valid | 参照が有効か |
どのノードにも Message ピンがあります。ここに書いた文字が、失敗したときにログへ出ます。

Message は必ず書いてください。 「テストが失敗した」だけ分かっても、何が違ったのか分からなければ調べ直しになります。「ダメージ適用後のHPが期待値と違う」のように、読んだ瞬間にどこを見るか分かる文にしてください(→ Print StringとOutput Log)。
小数の比較には注意。
Assert Equal (Float)には許容誤差(Tolerance)があります。小数の計算はごく小さな誤差が出るので、0.0001程度の余裕を持たせるのが普通です。Integerなら誤差はないので、そのまま比べて構いません。
走らせる
テストの実行は Session Frontend から行います。

- メニューの
ツール(Tools)→ Session Frontendを開く(日本語UIでは「セッションフロントエンド」) Automationタブを選ぶ(日本語UIでは「自動化」)- ツリーからテストを探してチェックを入れる。Functional Testは
Projectの下に並びます - 実行(Start Tests) を押す
すると、テスト用レベルが自動で読み込まれ、テストが走り、結果が一覧に出ます。緑が成功、赤が失敗です。
失敗した行を開くと、Assert の Message に書いた文が出ます。ここを読めば、どこを直すかが分かります。
一覧に自分のテストが出てこないときは、テスト用レベルにActorを置き忘れています。 Functional Testは「レベルに置かれていること」で発見されるので、Blueprintを作っただけでは一覧に現れません。
実践:HPが100→80になることをテストにする
ローグライクのダメージ計算、対戦ゲームのコンボ補正、RPGの属性倍率。数値が合っていることは、遊んで見ても気づきにくい部分です。ここでは ダメージ処理 の検証をテストにし、一度わざと赤くしてから直します。
用意するもの
| 項目 | 内容 |
|---|---|
BP_Enemy | 変数 MaxHealth(Float / 100.0)、CurrentHealth(Float / 100.0)。Event AnyDamage で CurrentHealth から Damage を引く |
| テスト用レベル | L_Test_Damage(床とライトのみ) |
| テストActor | BP_Test_Damage(親クラス: Functional Test) |
テストの中で使う値を先に決めます。
| 変数名 | 型 | 値 |
|---|---|---|
TestDamage | Float | 20.0 |
ExpectedHealth | Float | 80.0(100 − 20) |

テストの中身
BP_Test_Damage の Event Start Test に、4ステップで書きます。
Spawn Actor from ClassでBP_Enemyをテスト用レベルに出す(位置は原点で構いません)Apply Damage(Damaged Actor: 生成した敵、Base Damage:TestDamage=20.0)を呼ぶAssert Equal (Float)で、敵のCurrentHealthとExpectedHealth(80.0)を比べる。Toleranceは0.01、Messageは 「ダメージ適用後のHPが期待値と違う」Finish Test(Test Result = Succeeded)を呼ぶ

BP_Test_Damage(イベントグラフ)
Event Start Test
→ enemy = SpawnActorFromClass(Class = BP_Enemy, Transform = 原点)
→ ApplyDamage(
DamagedActor = enemy,
BaseDamage = TestDamage) // 20.0
→ AssertEqual_Float(
Actual = enemy.CurrentHealth,
Expected = ExpectedHealth, // 80.0
Tolerance = 0.01,
Message = "ダメージ適用後のHPが期待値と違う")
→ FinishTest(TestResult = Succeeded, Message = "")
Assert が失敗した時点でテストは失敗扱いになるので、Finish Test に Succeeded を渡しておけば問題ありません(Assertが通ればそのまま成功します)。
まず、わざと赤くする
ここが重要です。テストが本当に機能しているかを確かめます。
BP_Enemy の Event AnyDamage の減算を、わざと壊してください。CurrentHealth - Damage を CurrentHealth - 0 に変える、あるいは減算を丸ごと外します。
その状態で Session Frontend からテストを走らせると、赤く失敗します。
行を開くと、Message に書いた 「ダメージ適用後のHPが期待値と違う」 が出ています。期待値 80.0 に対して実際は 100.0 だった、という情報も一緒に出ます。
この赤を見ることが、テストを書く目的の半分です。 最初から緑のテストは、何も検証していない可能性があります(Assertの繋ぎ忘れなど)。
直して、緑にする
減算を元に戻し(CurrentHealth - Damage)、もう一 度テストを走らせてください。緑になります。
これで、「攻撃でHPが20減る」という仕様が機械的に守られている状態になりました。今後どこを直しても、このテストを走らせればこの1点が壊れていないことを一瞬で確認できます。
うまくいかないときの切り分けです。
- テストが一覧に出てこない →
BP_Test_Damageをテスト用レベルに置いていません。Blueprintを作っただけでは発見されません - タイムアウトで失敗する →
Finish Testを呼んでいません。すべての経路から必ず呼んでください Assert Equal (Float)が微妙な差で失敗する →Toleranceが0.0です。0.01程度を入れてください- 敵が生成されない →
Spawn Actor from ClassのTransformが未設定か、Collision Handlingの設定で生成が拒否されています
ポイントは2つです。
- 一度赤くしてから緑にする: わざと壊して失敗を見ることで、そのテストが本当に効いていると確認できます。緑だけを見て安心しないでください
Messageに「どこを見るか」を書く: 半年後の自分が読んで、すぐ調べ始められる文にします。失敗の一覧に並ぶのはこの文だけです
バグを見つけて直したときは、そのバグを再現するテストを1つ足すのが効果的です。Blueprint Debugger で原因を突き止めたら、同じ条件をテストに落とし て、二度と同じ場所で踏まないようにします。
おまけ:先に知っておくと良いこと
テストは増やしすぎない。 個人開発で「全部テストする」を目指すと、テストの保守にゲーム制作の時間を食われます。壊れると痛い所、一度壊れた所だけに絞ってください。目安は、ダメージ計算・セーブとロード・進行フラグの3つです。どれも壊れても見た目には気づきにくく、気づいたときの被害が大きい部分です。
コマンドラインから走らせられる。 Session Frontendを開かずに、実行ファイルの引数でテストを走らせることもできます。「毎晩自動で全テストを走らせる」といった運用(CI)に使えますが、個人開発ではまず手で走らせる習慣を付けるほうが先です。
日本語UIでは表記が変わる。 Session Frontend は「セッションフロントエンド」、Automation タブは「自動化」です。英語のチュートリアルを見ながら日本語UIで探すと迷うので、言語設定を英語にしておくと詰まりにくいです(→ 初期設定)。
パッケージ前に走らせる習慣を。 パッケージ化 の前にテストを一度走らせておくと、「配布してから気づく」を減らせます。テストが5個あれば、確認は数十秒です。
まとめ
- 機能が増えると 手での確認は必ず省かれる 。省いた所が壊れる
- UEのテストは2種類。 Blueprint勢は Functional Test から
- Functional Testは テ スト用レベルに置くActor 。作る感覚はゲーム制作と同じ
- 判定は
Assert系ノード 。Messageに「どこを見るか」を書く Finish Testを必ず呼ぶ 。忘れるとタイムアウトで失敗する- 一度わざと赤くしてから緑にする 。最初から緑のテストは疑う
全部をテストする必要はありません。壊れたら痛い1箇所から始めてください。あなたのゲームで、壊れても気づきにくいのはどこでしょうか。