オフィスアワーがそろそろ始まるよ!()

アサーション

プログラムが正しく動作していることをテストするための機能です。次に学ぶユニットテストとの違いは、ユニットテストがテストブロック内で使用されるのに対して、アサーションはテストブロック以外、つまりプロダクトコード内で使用されることです。

std.debug.assert

アサーションで利用する関数は、標準ライブラリのstd.debug.assert関数です。assert関数はブール型の引数を1つ受け取ります。この引数がfalseの場合、アサーションが失敗し、安全性保護付き未定義動作が発生します。安全性保護付き未定義動作の挙動は、ビルドモードによって異なります。そのことについては、ビルドモードによる違いで説明します。

次のコードのように、assert関数の引数がtrueであればアサーションがOKであることを意味します。

fn assertOk() void {
    assert(true);
}

逆に、assert関数の引数がfalseであればアサーションがNGとなります。

fn assertNg() void {
    assert(false);
}

もう少し意味のある例を見てみます。整数同士の除算の除数が0の場合、ゼロ除算例外が発生し、正しい除算の結果が得られません。そこで、除数が0でないことをassertで保証するコード例を示します。

ノート: Zenの除算 (/) オペレータはデフォルトで除数が0かどうかをチェックするので、実際には次のようなコードを書く必要はありません。

fn div(dividend: u32, divisor: u32) u32 {
    assert(divisor != 0);
    return dividend / divisor;
}

この関数の除数 (divisor) に対して、0を与えて呼び出してみます。

const ok = std.testing.ok;
fn div(dividend: u32, divisor: u32) u32 {
    assert(divisor != 0);
    return dividend / divisor;
}

test "div" {
    ok(div(2, 0) == 0);
}

結果は次のようにassertが失敗したことで、unreachableに到達した、という実行時エラーになります。

2/2 src.assert.test "div"...reached unreachable code
zen/build/lib/zen/std/debug.zig:216:14: 0x20406b in std.debug.assert (test)
    if (!ok) unreachable; // assertion failure
             ^
src/assert.zen:17:11: 0x2047cc in src.assert.div (test)
    assert(divisor != 0);
          ^
...

ビルドモードによる違い

assertはビルドモードがDebugモードかReleaseSafeモードの場合のみパニックを発生させます。ReleaseFastモードおよびReleaseSmallモードでは、assertは最適化によって取り除かれます。

試しに、assert_release.zenというファイルを作成し、次のコードを入力して下さい。

const std = @import("std");
const assert = std.debug.assert;

test "assert in release fast" {
    assert(false);
}

このassertfalseを引数として与えているため、実行時エラーになるはずです。実際に、次のコマンドでテスト実行すると、実行時エラーになります。

$ zen test assert_release.zen

これは、ZenはデフォルトではDebugモードでビルドを行うためです。次に、以下のコマンドでテストを実行してみて下さい。

$ zen test src/assert_release.zen --release-fast

テストはパスしてしまいます。

1/1 test "assert in release fast"...OK
All tests passed.

std.debug.assertDebugモードで開発している間や、ReleaseSafeでソフトウェアをリリースする場合の防護柵として活用するべきと言えます。

☰ 人の生きた証は永遠に残るよう ☰
Copyright © 2018-2019 connectFree Corporation. All rights reserved.
Zen, the Zen three-circles logo and The Zen Programming Language are trademarks of connectFree corporation in Japan and other countries.