この記事でのバージョン
Unity 5.6.1f1
はじめに
今回はタイトル通り、UnityでAssertを使ってみよう!という記事です。
//IsTrueは条件が真である事を確認する(偽であればエラーを出す) Assert.IsTrue(_notActiveGameObject.activeSelf, "_notActiveGameObjectがアクティブではありません!");
なお、C#にあるAssert(Unityでは使えない?)ではなく、Unity独自の話なのであしからず。
Assertとは
そもそもAssert(Assertion)とはなんぞやという話からですが、とりあえず目ぼしいサイトから抜粋。
プログラムの前提として満たされるべき条件を記述し、実行時にそれが満たされていない場合にエラーや例外を発生させたり、メッセージを表示して処理を中断したりする機能をアサーションチェックあるいは略してアサーションという。プログラム中のバグや不具合、論理の矛盾を発見するのに使われる。
アサーションは開発時のみ使われリリース時には不要なため、多くの言語処理系などではアサーション関連のコードを削除しなくても有効・無効を切り替えられるようになっていることが多い。
重要なのは以下の2点。
「プログラム中のバグや不具合、論理の矛盾を発見するのに使われる。」
「アサーションは開発時のみ使われリリース時には不要」
端的に言えば「開発時にバグを発見するのに使われるモノ」と言った感じでしょうか。
具体的にはバグが発生した時(想定外の数値になった時)に即エラーを発生させ通知するやり方で、
「想定外の数値になってもエラーは発生せず、ゲームはそのまま進んでしまい、バグが発見しにくい」
みたいな時に特に有効です。
例えば「_hp(int)が常に0以上でないといけない」という場合を素直に実装すると以下のような感じ。
//DebugBuild時は、_hpが0以上かチェックする if(Debug.isDebugBuild && _hp < 0){ //HPが0未満ならエラーを表示 Debug.LogError("HPが0未満になっています!(_hp : " + _hp + ")"); }
これを専用のモノを使う事で、簡単かつ使い易い実装に出来るようになるわけです。
Assert
さて本題のUnityでAssertを使う方法ですが、単純にAssertというモノを使うだけだったりします。
しかしここで一つ問題が、
なんとUnityにはAssertというクラスとメソッドが別々に二つ存在するのです。
Debug.Assert
まず一つ目がDebug.Assert(Format)。Debug.Logでお馴染みのDebugクラスのメソッドです。
使い方はTrueにならないといけない条件(False=バグになる条件)を引数にするだけです。
先ほど例に挙げた
「_hp(int)が常に0以上でないといけない」という場合には以下のような感じになります。
//_hpが0以上かチェックする Debug.Assert(_hp >= 0);
Assert実行時に_hpが0未満になっていると以下のようにエラーが表示されるようになり、
バグを簡単に発見できるようになります。
また、Debug.Logの要領で、第二引数にエラー時のメッセージを設定する事も可能です。
//_hpが0以上かチェックする Debug.Assert(_hp >= 0, "HPが0未満になっています!(_hp : " + _hp + ")");
なお、Build SettingsのDevelopment Buildが有効な時だけ実行されるので、
リリース時に簡単に無効化する事が出来ます。
Assertions.Assert
次に二つ目がAssertions.Assertというクラスです。
使用時にはusing UnityEngine.Assertions;が必要になります。
使い方はDebug.Assertと同様に
条件を第一引数、エラー時のメッセージを第二引数にしてメソッドを実行するだけ。
ただし、判定したい条件によってメソッドを使い分ける必要があります。
//IsTrueは条件が真である事を確認する(偽であればエラーを出す) Assert.IsTrue(_notActiveGameObject.activeSelf, "_notActiveGameObjectがアクティブではありません!"); //IsFalseは条件が偽である事を確認する(真であればエラーを出す) Assert.IsFalse(_activeGameObject.activeSelf, "_activeGameObjectがアクティブです!"); //IsNullはnullである事を確認する(nullでなければエラーを出す) Assert.IsNull(_notNullGameObject, "_notNullGameObjectがnullではありません!"); //IsNotNullはnullでない事を確認する(nullであればエラーを出す) Assert.IsNotNull(_nullGameObject, "_nullGameObjectはnullです!"); //AreEqualは値が等しい事を確認する(等しく無ければエラーを出す) Assert.AreEqual("Player", gameObject.tag, "このGameObjectはPlayerではありません!(tag : " + gameObject.tag + ")"); //AreNotEqualは値が等しくない事を確認する(等しければエラーを出す) Assert.AreNotEqual(5, gameObject.layer, "このGameObjectのLayerが5になっています!(layer : " + gameObject.layer.ToString() + ")"); //AreApproximatelyEqualは値がほぼ等しい事を確認する、float用のAreEqual(ほぼ等しく無ければエラーを出す) Assert.AreApproximatelyEqual(0.0f, transform.position.x, "xが0ではありません!(x : " + transform.position.x.ToString() + ")"); //AreNotApproximatelyEqualは値がほぼ等しくない事を確認する、float用のAreNotEqual(ほぼ等しければエラーを出す) Assert.AreNotApproximatelyEqual(360, transform.position.y, "yが360です!");
なお、Debug.Assert同様にBuild SettingsのDevelopment Buildが有効な時だけ実行されるので、
リリース時に簡単に無効化する事が出来ます。
Debug.Assert vs Assertions.Assert
さてさて、Assertの使い方が分かったのは良いんですが、二つのやり方があるとなると
どっちを使えば良いの?という話になります。
以下はそんな疑問を質問しているページです。
上記のページによると、
Assertions.AssertはDebug.Assertの後に実装されたもので、
Assertions.AssertはDebug.Assertをラップしている。
との事。
つまり、Assertions.AssertはDebug.Assertをより使い易くした便利クラスみたいなものらしいです。
という事で基本的にAssertions.Assertを使えば良いと思います。
状況に応じてメソッドを分けられるのも良いですしね。