(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

UnityでAssertを使う(Debug.Assert と Assertions.Assert)【Unity】


このエントリーをはてなブックマークに追加

この記事でのバージョン
Unity 5.6.1f1


はじめに

今回はタイトル通り、UnityでAssertを使ってみよう!という記事です。

//IsTrueは条件が真である事を確認する(偽であればエラーを出す)
Assert.IsTrue(_notActiveGameObject.activeSelf, "_notActiveGameObjectがアクティブではありません!");

f:id:kan_kikuchi:20170709081523j:plain


なお、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未満になっていると以下のようにエラーが表示されるようになり、

バグを簡単に発見できるようになります。


f:id:kan_kikuchi:20170709071220j:plain


また、Debug.Logの要領で、第二引数にエラー時のメッセージを設定する事も可能です。

//_hpが0以上かチェックする
Debug.Assert(_hp >= 0, "HPが0未満になっています!(_hp : " + _hp + ")");

f:id:kan_kikuchi:20170709071427j:plain


なお、Build SettingsのDevelopment Buildが有効な時だけ実行されるので、

リリース時に簡単に無効化する事が出来ます。


f:id:kan_kikuchi:20170709071611j:plain


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です!");

f:id:kan_kikuchi:20170709081841j:plain


なお、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を使えば良いと思います。

状況に応じてメソッドを分けられるのも良いですしね。