無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、GD スクリプトで作成した機能のユニットテストをする際に便利な無料アセット GUT で、ユニットテストを行う前後に呼び出すイベント関数 before_each(), after_each() を用いて、テストの共通処理を定義して単体テストを実行します。
※ 3.x 系で 4.x 系が用意されていて 4.2 と書かれているので公式なサポートではないかもしれませんが 4.3 でも動作しました。
※ GodotEngine 4.3 を使用しています。.NET 版ではありません。
※ GUT アセットのバージョンは 9.3.0 です。
※スクリプトは自己責任でご使用ください。
前回の記事
前回は、無料アセット GUT で、指定したフォルダ内に配置した公式のサンプルスクリプトでユニットテストを実行する手順を紹介しました。
テストはフォルダ・ファイル・関数単位で行える
前回の記事では、 GUT タブの右側の Include Subdirs リストに指定したフォルダ内の全てのテスト用スクリプトファイルの全てのテスト関数を、左上の Run All ボタンを押してテストしました。
そのあとに GUT タブの左上の Run All ボタンの右側をみると、現在開いているテスト用スクリプトの名前が書かれたボタンが追加され、さらにその右側には現在カーソルを置いている位置のテスト関数の名前が書かれたボタンが追加されていました。
ファイル名・関数名の書かれたボタンを押すと、Run All ボタンを押したときのようにフォルダ内の全てではなく、1つのファイルに書かれた全てのテストや、選択しているテスト関数だけをテストすることができます。
ユニットテストの前後に共通の処理を定義
以下のテスト用スクリプトでは、3つの各テスト関数の最初の4行で全く同じ処理を行っています。
また、return の前の1行の処理も同じです。
※処理の説明についてはスクリプト内のコメントを参照してください。
具体的には、ハイライト表示されている、6-9, 21-22, 27-30, 42-43, 48-51, 63-64行目が各テスト関数の共通の処理です。
extends GutTest
## SakuraCrowdUtil クラスで定義されたユーティリティ関数のテストを行います。
## SakuraCrowdUtil.to_cell_pos_ceil 関数の境界値(境界値 ± 0)の単体テストです。
func test_to_cell_pos_ceil_1():
# テスト対象関数の TileMapLayer 型の引数の作成
var tilemap_layer = TileMapLayer.new() # オブジェクトを生成します。
tilemap_layer.tile_set = TileSet.new() # タイルセットリソースを新規作成して割り当てます。
tilemap_layer.tile_set.tile_size = Vector2i(16, 16) # タイルセットのタイル(セル)のサイズを設定します。
# テスト対象関数の Vector2 型の引数の作成
var global_pos = Vector2(16, 0) # タイルサイズの境界値 ± 0 の値を設定
# 期待する値を指定します。
var correct = Vector2i(1, 0)
# テスト対象関数を呼び出して結果を得ます。
var result: Vector2i = SakuraCrowdUtil.to_cell_pos_ceil(global_pos, tilemap_layer)
# GUT の関数で、結果の値と期待する値が同じかどうかをテストします。
assert_eq(result, correct)
# 動的に生成した TileMapLayer オブジェクトを破棄します。
tilemap_layer.free()
return
## SakuraCrowdUtil.to_cell_pos_ceil 関数の境界値(境界値 - 1)の単体テストです。
func test_to_cell_pos_ceil_2():
# テスト対象関数の TileMapLayer 型の引数の作成
var tilemap_layer = TileMapLayer.new() # オブジェクトを生成します。
tilemap_layer.tile_set = TileSet.new() # タイルセットリソースを新規作成して割り当てます。
tilemap_layer.tile_set.tile_size = Vector2i(16, 16) # タイルセットのタイル(セル)のサイズを設定します。
# テスト対象関数の Vector2 型の引数の作成
var global_pos = Vector2(15, -1) # タイルサイズの境界値 - 1 の値を設定
# 期待する値を指定します。
var correct = Vector2i(1, 0)
# テスト対象関数を呼び出して結果を得ます。
var result: Vector2i = SakuraCrowdUtil.to_cell_pos_ceil(global_pos, tilemap_layer)
# GUT の関数で、結果の値と期待する値が同じかどうかをテストします。
assert_eq(result, correct)
# 動的に生成した TileMapLayer オブジェクトを破棄します。
tilemap_layer.free()
return
## SakuraCrowdUtil.to_cell_pos_ceil 関数の境界値(境界値 + 1)の単体テストです。
func test_to_cell_pos_ceil_3():
# テスト対象関数の TileMapLayer 型の引数の作成
var tilemap_layer = TileMapLayer.new() # オブジェクトを生成します。
tilemap_layer.tile_set = TileSet.new() # タイルセットリソースを新規作成して割り当てます。
tilemap_layer.tile_set.tile_size = Vector2i(16, 16) # タイルセットのタイル(セル)のサイズを設定します。
# テスト対象関数の Vector2 型の引数の作成
var global_pos = Vector2(17, 1) # タイルサイズの境界値 + 1 の値を設定
# 期待する値を指定します。
var correct = Vector2i(2, 1)
# テスト対象関数を呼び出して結果を得ます。
var result: Vector2i = SakuraCrowdUtil.to_cell_pos_ceil(global_pos, tilemap_layer)
# GUT の関数で、結果の値と期待する値が同じかどうかをテストします。
assert_eq(result, correct)
# 動的に生成した TileMapLayer オブジェクトを破棄します。
tilemap_layer.free()
return
このように、ユニットテストの準備と後片付けといった共通の処理は、 GUT が用意したイベント関数 before_each(), after_each() に定義できます。
例では 4 ~ 19 行目に before_each(), after_each() イベント関数の処理を定義して、その内部で用いる変数は 5 行目に定義しています。
これにより、このファイルのユニットテストを行うと以下のように、各テスト関数を呼び出す前後に before_each() と after_each() 関数が実行され、各テスト関数の共通の準備と後片付けの処理を1度定義するだけで実装できました。
before_each() → test_to_cell_pos_ceil_1() → after_each()
→ before_each() → test_to_cell_pos_ceil_2() → after_each()
→ before_each() → test_to_cell_pos_ceil_3() → after_each()
extends GutTest
## SakuraCrowdUtil クラスで定義されたユーティリティ関数のテストを行います。
## TileMapLayer 型オブジェクトを引数とする複数のテストケースで共通して用いる変数です。
var tilemap_layer = null
## テストケースごとにテスト実行前に呼び出される GUT のイベント関数です。テスト前の共通の処理を書きます。
func before_each():
# テスト対象関数の TileMapLayer 型の引数の作成
tilemap_layer = TileMapLayer.new() # オブジェクトを生成します。
tilemap_layer.tile_set = TileSet.new() # タイルセットリソースを新規作成して割り当てます。
tilemap_layer.tile_set.tile_size = Vector2i(16, 16) # タイルセットのタイル(セル)のサイズを設定します。
return
## テストケースごとにテスト実行後に呼び出される GUT のイベント関数です。テスト後の共通の処理を書きます。
func after_each():
# 動的に生成した TileMapLayer オブジェクトを破棄します。
tilemap_layer.free()
return
## SakuraCrowdUtil.to_cell_pos_ceil 関数の境界値(境界値 ± 0)の単体テストです。
func test_to_cell_pos_ceil_1():
# テスト対象関数の Vector2 型の引数の作成
var global_pos = Vector2(16, 0) # タイルサイズの境界値 ± 0 の値を設定
# 期待する値を指定します。
var correct = Vector2i(1, 0)
# テスト対象関数を呼び出して結果を得ます。
var result: Vector2i = SakuraCrowdUtil.to_cell_pos_ceil(global_pos, tilemap_layer)
# GUT の関数で、結果の値と期待する値が同じかどうかをテストします。
assert_eq(result, correct)
return
## SakuraCrowdUtil.to_cell_pos_ceil 関数の境界値(境界値 - 1)の単体テストです。
func test_to_cell_pos_ceil_2():
# テスト対象関数の Vector2 型の引数の作成
var global_pos = Vector2(15, -1) # タイルサイズの境界値 - 1 の値を設定
# 期待する値を指定します。
var correct = Vector2i(1, 0)
# テスト対象関数を呼び出して結果を得ます。
var result: Vector2i = SakuraCrowdUtil.to_cell_pos_ceil(global_pos, tilemap_layer)
# GUT の関数で、結果の値と期待する値が同じかどうかをテストします。
assert_eq(result, correct)
return
## SakuraCrowdUtil.to_cell_pos_ceil 関数の境界値(境界値 + 1)の単体テストです。
func test_to_cell_pos_ceil_3():
# テスト対象関数の Vector2 型の引数の作成
var global_pos = Vector2(17, 1) # タイルサイズの境界値 + 1 の値を設定
# 期待する値を指定します。
var correct = Vector2i(2, 1)
# テスト対象関数を呼び出して結果を得ます。
var result: Vector2i = SakuraCrowdUtil.to_cell_pos_ceil(global_pos, tilemap_layer)
# GUT の関数で、結果の値と期待する値が同じかどうかをテストします。
assert_eq(result, correct)
return
テストの実行
下パネル GUT タブの Run All ボタンの右側にある現在開いているテスト用スクリプトファイルの名前をクリックすると、そのファイルの各テスト関数が正常に実行されました。
実行ウィンドウの 2 ~ 4 行目に表示された関数名から、3つのテスト関数が実行されたことが確認できます。
まとめ
今回は、無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、GD スクリプトで作成した機能のユニットテストをする際に便利な無料アセット GUT で、ユニットテストを行う前後に呼び出すイベント関数 before_each(), after_each() を用いて、テストの共通処理を定義して単体テストを実行しました。
参照サイト Thank You!
- Godot Engine – Free and open source 2D and 3D game engine
- GUT – Godot Unit Testing (Godot 4) – Godot Asset Library
- Gut 9.3.0 (Godot 4.2) — GUT 9.3.0 documentation
- Quick Start — GUT 9.3.0 documentation
- GUT を使用した Godot でのテスト駆動開発 (チュートリアル) – YouTube
記事一覧 → Compota-Soft-Press
コメント