Movatterモバイル変換


[0]ホーム

URL:


ぐるぐる~

この広告は、90日以上更新していないブログに表示しています。

続・そろそろPower Assertについてひとこと言っておくか

3年前にこんな記事をあげました。

bleis-tift.hatenablog.com

3行でまとめると、

  • Power Assertはユニットテストのためにほしかったものではない
  • 欲しいのは結果の差分
  • 誰か作って!

というエントリでした。そしたらid:pocketberserker が作ってくれました!

github.com

PowerAssertより強そうな名前でいい感じです。

Power Assertは時代遅れ、今はMuscle Assertだ!的な話かな?

— 裸のWPF/MVVMを書く男(マン) (@gab_km)2016年6月1日

MuscleAssertの使い方

このライブラリは、PersimmonというF#用のテスティングフレームワークを拡張するライブラリとして作られています。ただ、ざっくり概要をつかむだけであればどちらも知らなくても問題ありません。このライブラリでできることはほぼ1つだけです。

openPersimmonopenPersimmon.Syntax.UseTestNameByReflectionopenPersimmon.MuscleAssertletadd x y= x+ ylet ``add235を返す``()= test{do! add23===5}

以上。簡単。これを実行しても成功してしまって面白みがないので、わざと間違ってみましょう。

openPersimmonopenPersimmon.Syntax.UseTestNameByReflectionopenPersimmon.MuscleAssertletadd x y= x+ x// ミス!let ``add235を返す``()= test{do! add23===5}

これをPersimmon.Consoleで実行すると、

 Assertion Violated: add 2 3が5を返す 1. .      left  4      right 5

こんなエラーが出てきました。普通ですね。

では、例えばこんなJSONがあったとしましょう。

{"widget":{    "debug": "on",    "window":{        "title": "Sample Konfabulator Widget",        "name": "main_window",        "width":500,        "height":500},    "image":{         "src": "Images/Sun.png",        "name": "sun1",        "hOffset":250,        "vOffset":250,        "alignment": "center"},    "text":{        "data": "Click Here",        "size":36,        "style": "bold",        "name": "text1",        "hOffset":250,        "vOffset":100,        "alignment": "center",        "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"}}}

これを読み込む関数を定義したとして、その関数をテストしたいですよね。

letexpected=let ``JSONが読み込める``()= test{do! read json=== expected}

read 関数の実装にミスがあり、textvOffsethOffset の値を使ってしまったとしましょう。このテストを実行すると、下記のようなエラーメッセージが表示されます。

 Assertion Violated: JSONが読み込める 1. .text.vOffset      left  250      right 100

textvOffset の値が左は250 だったけど、右は100 だった、ということが一目瞭然です。

MuscleAssert VS PowerAssert

MuscleAssertとPowerAssertの目的ははっきりと分かれています。MuscleAssertが最初からテスティングフレームワークアサーションを書くために特化しているのに対して、PowerAssertは(テストではなく)表明に使うことを前提にデザインされています。

表明手段

表明手段としてのPowerAssertはとても便利です。言語内蔵のassert は、条件式がfalse の場合に何やらメッセージを出しますが、「どこで表明がfalse と評価された」くらいの情報しか持っていません。メッセージをカスタマイズすることはできますが、文字列で指定する必要があるため「どうなったか」を埋め込むのは大変です。

PowerAssertは、言語内蔵のassert をそのままに表示されるメッセージをリッチにしてくれます。表明として埋め込んだ式の「部分式の値」がメッセージとして表示されるため、「どの式の評価値が想定と違うのか」を調べるための情報をコーディングのコストを払わずに得られるようになるのです。

対してMuscleAssertはそもそも、Persimmon.MuscleAssertはPersimmon用のライブラリとして作られているため、Persimmonに依存しており単体で使えるものではありません。表明に使えたとしても、MuscleAssertは式全体の評価結果の差分を出すため、ほしい情報である「どの式の評価値が想定と違うのか」を調べるための情報はそこに乗っていないでしょう。

表明手段としては、PowerAssertの圧勝です。

ユニットテストアサーション

しかし、MuscleAssertがやりたかったのは表明ではありません。ユニットテストアサーションとして使いたかったのです。

MuscleAssertが例えばJSONのようなネストした構造に対するテストに強そうだ、というのは先ほど紹介した例で分かると思います。XMLJSONYAMLは当然として、そもそもクラス自体が何かを内部に持っているネスト構造をしているため、ネストした構造をそのまま比較してもわかりやすいメッセージが出力されるMuscleAssertは便利です。

対してPowerAssertはこの例には貧弱です。

let ``JSONが読み込める``()= test{do! read json=== expected}

このテストが失敗するとして、PowerAssertで表示されるのは

  • json 変数の中身
  • read json の結果
  • expected の中身
  • read json === expectedfalse になったということ

ですかね。どれもドバドバと大量の出力をするわりに、本当に欲しい「どこがどう違うのか?」という情報はそこから得るのは容易ではありません。diffツールを使って外部でdiffとるとかしたことある人も多いんじゃないでしょうか?

そもそも、テストでactual 側に部分式が出てうれしいほど何かを書くことって多いのか?というのも疑問です。このテストのように、多くのテストでは期待値との一点比較ができればいいのではないでしょうか?

ちなみに、MuscleAssertでは一度に複数の箇所の間違いを出してくれますので、小さいテストをまとめるのも容易です。

1. .image.hOffset      left  500      right 250    .image.vOffset      left  500      right 250    .text.vOffset      left  250      right 100    .text.alignment      left  centre      right center    @@ -1,6 +1,6 @@     cent    -re    +er

MuscleAssertの弱点

MuscleAssertの弱点は、一点比較しかできないところです。そのため、浮動小数点数を含むデータ構造を、浮動小数点数の一致範囲を指定して比較、ということは現状ではできません。また、大小比較などもサポートしていません。

現状でこれらをテストしたい場合は、MuscleAssertを使わずにテストするしかありません。今のところ、これで困ったことはありません(そういうテストが必要なドメインで仕事をしていない)。

まとめ

まとめも3行で。

  • MuscleAssert便利
  • テストのためのアサーションライブラリとしてはPowerAssertよりも便利
  • 弱点はある。でも自分が困っていないから放置

みなさんも自分が使っている言語でMuscleAssertを実装してみてはいかがでしょう?便利ですよ。

検索

引用をストックしました

引用するにはまずログインしてください

引用をストックできませんでした。再度お試しください

限定公開記事のため引用できません。

読者です読者をやめる読者になる読者になる

[8]ページ先頭

©2009-2025 Movatter.jp