D言語の単体テストが更に便利になる silly の紹介
はじめに
D言語の単体テスト機能をさらに便利にするために作られた silly
というパッケージの紹介です。
これは「単体テストの実行」をリッチにするライブラリで、最近はDUBレジストリの人気パッケージでもTOP3の常連になってきています。
導入は非常に簡単ながら、ざっくり以下のことができるようになります。
ぜひ使ってみて下さい。
-
unittest
ブロック毎に結果の成否をカウントする -
unittest
ブロック毎の処理時間を表示する - テストに名前を付ける(Naming Tests)
- テストを複数スレッドで分散して実行する
- テストを正規表現でフィルタする
前置き(準備)
まず適当なパスに普通にプロジェクトを作っておきます。
dub init sandbox-silly -n
cd sandbox-silly
続けて単体テストを書きます。2つ書いておきます。
import std.stdio;
void main()
{
writeln("Edit source/app.d to start your project.");
}
unittest
{
assert(1 + 2 == 3);
}
unittest
{
assert(2 + 3 == 5);
}
1回実行してみます
dub test
Running .\sandbox-silly.exe
1 unittests passed
app
というモジュールでテストが全部成功したので、 1 unittests
がパスしたよ、となってます。
基本的に全部成功する前提であればこれで十分ですが、TDDやBDDだと開発中は失敗続きになるので少しわかりづらい部分もあります。
silly
を導入すると、これがもっといい感じの表示になります。
導入
ではここに silly
を導入していきます。
やることは2つです。
-
dub
の設定ファイルに単体テスト用のunittest
というconfiguration
を追加し、依存関係を追加する -
main
関数のあるプログラムであれば条件コンパイル等で除外しておく
依存関係の追加
sillyの最新バージョンが分からないので、とりあえず dub add
コマンドで最新版を追加して書き換えます。
dub add silly
{
"name": "sandbox-silly",
"dependencies": {
"silly": "~>1.0.2"
}
}
2020年6月14日現在、最新バージョンは 1.0.2
でした。
ここから dub test
で使われる unittest
という名前の configuration
を追加し、dependencies
も移動します。
また、元の実行ファイルを作る設定も残しておくため executable
というのも書いておきます。こちらは default
とかでも良いです。
{
"name": "sandbox-silly",
"configurations": [
{
"name": "executable"
},
{
"name": "unittest",
"dependencies": {
"silly": "~>1.0.2"
}
}
]
}
エントリポイントの除外
silly
は独自のエントリポイントを持っているライブラリなので、アプリ側で main
関数を書かないようにする必要があります。
ライブラリであれば何もしなくて大丈夫ですが、今回は main
関数があるので version (unittest)
を使い条件コンパイルで消しておきます。
version (unittest) {}
else
{
void main()
{
writeln("Edit source/app.d to start your project.");
}
}
実行
さて、導入はこれだけです。もう1回実行してみましょう。
テスト実行のコマンドは変わりません。
dub test
テスト結果
結果の表示が変わりました。色付きなので画像にしています。
unittest
のブロック単位でカウントされ、どのテストが成功したのか失敗したのか、が色付きで表示されます。
チェックマークの直後がモジュール名、その次がテスト名(単体テストの関数名、Lの後が行数)です。
また実行時間が表示されるのもいい感じですね。
失敗時
assert(2 + 3 == 6)
として失敗させてみます。
failedのほうが1つ増えました。
ちなみにVSCodeならスタックトレースのファイル名のあたりにマウスを載せるとCtrl+Clickで失敗した場所に移動できます。
と、以上が基本的な使い方です。
以下、さらに便利な部分について解説します。
機能
名前付きテスト
単体テスト1つ1つに名前を付けられます。
分かりやすい名前をつけておくと結果もわかりやすくなります。
@("1+2==3")
unittest
{
assert(1 + 2 == 3);
}
@("...")
の部分は言語的には UDA
(User Defined Attribute)という機能で、関数に文字列を属性として付与しています。
silly
はこの文字列の UDA
をテストの名前として認識します。
文字列の UDA
は言語の標準機能なので、 silly
を import
したり特別覚えることもないのは良いところかなと思います。
マルチスレッド化
silly
のテスト実行は、既定で複数スレッドで実行されます。
単体テストは独立順不同で実行できるという想定なので、マルチスレッド化すれば単純に早く終わるだろう、という感じです。
しかし、グローバル変数を触るようなテスト、外部ファイルを書いたりするテストはマルチスレッドだと具合が悪いので無効化したいときもあります。
無効化するときは、引数として、 -t 1
や --threads=1
といった感じで指定します。
0
はコア数から自動で決定、あとは好きな数を設定すればOKです。
dub test -- -t 1
なお、引数の指定で dub test
の後に --
と挟んでいる点に注意が必要です。
dub
そのものに対する引数と dub test
の実行に関わる引数を分ける意味があります。
テストのフィルタリング
silly
の目玉機能です。
モジュール名やテスト名に対して正規表現でフィルタリングすることができます。
含めたい場合は、 -i
や --include
で指定、
除外する場合は、 -e
や --exclude
で指定します。
dub test -- -i app
dub test -- -i app -e 1\+2
※ dub test
の後に --
と挟んでいるのに注意です
今書いてるモジュールだけテストしたいときなど、割と気軽にテストを絞れるので非常に便利です。
また名前の付け方によって優先度を表現したりできるので、時間のかかるテストを除外するなどしたいときはこのあたりで調整すると良さそうですね。
複数スレッドで実行してほしくないグループ毎に名前を付けておいて、それを -i
と -t 1
で調整すれば高度な制御もできるようになります。
詳細表示
-v
や --verbose
というフラグを付けることで詳細表示モードになります。
- テスト毎に実行時間が表示される
-
silly
のテストランナーも含めたスタックトレースが表示される
遅いテストを特定できるので、除外したり高速化することで日頃の開発が更に効率的になると思います。
テストランナーの差し替え
D言語は、単体テストのテストランナー切り替え機能をランタイム機能として提供しています。
Runtime.extendedModuleUnitTester = &customTester;
という感じで差し替えるだけでよく、自力で書くのも簡単です。
以下にサンプル含めたドキュメントがあるので、興味がある方は参照してみてください。
-
Runtime.extendedModuleUnitTester
Author And Source
この問題について(D言語の単体テストが更に便利になる silly の紹介), 我々は、より多くの情報をここで見つけました https://qiita.com/lempiji/items/4e2968208a8dd9b17ead著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .