Igor Proの最小構成のテスト関数群を書いた

はじめに

Igor Proのプロシージャを書いていると,改良したつもりが既存の機能を壊してしまっていた,ということがよくあります. よくありますがよくないです.何より「改良が怖い」というのが精神衛生上とてもよくないです.

で,調べたところソフトウェア開発には「単体テスト」なる技法がある模様. 関数の振る舞いをチェックするテストコードを用意しておき,変更を行うたびにそのテストがパスすることを確認するのだとか.

よし,それじゃあ(よく分かってないけど)Igor Proでも単体テストしよう!と思い立ち,単体テスト用のプロシージャを探したところ次のふたつを見つけました.

github.com

github.com

上記2つのプロシージャはどうも

を参考にして作られているようです.汎用プログラミング言語のテスティングフレームワークを参考にしていて高機能なのですが,単純な手続き型のIgor Proには機能過多かなぁ...と思いました. そもそもIgor Proユーザにしめるプログラマの割合ってそれほど大きくないはずで,「既存のテスティングフレームワークに似ている」はあまりメリットでもない気がしました.

なので,Igor Proに必要な,ミニマルな単体テスト関数群を書きました.

github.com

使い方

MinTest.ipfを読み込むと,以下の4つの関数が使えるようになります.

  • eq_var
  • eq_str
  • eq_wave
  • eq_text

publicな関数はこれだけ*1.ミニマルです.以下のようにTestで始まる関数を定義して,その中で使います.

Function TestDemo()

  eq_var(word_count("it is a test"), 4)
  eq_str(hello_world(), "Hello, world!")
  eq_wave(fibonacci(5), {1,1,2,3,5})
  eq_text(fizzbuzz(5), {"1","2","Fizz","4","Buzz"})

End

Function word_count(s)
    String s
    return ItemsInList(RemoveFromList(" ", s, " "), " ")
End

Function/S hello_world()
    return "Hello, world"
End

Function/WAVE fibonacci(n)
    Variable n
    Make/FREE/N=(n) w = 1
    w[2,inf] = w[p-1] + w[p-2]
    return w
End

Function/WAVE fizzbuzz(n)
    Variable n
    Make/FREE/T/N=(n) w = Num2Str(p+1)
    w = SelectString(mod(p+1,  3), "Fizz", w)
    w = SelectString(mod(p+1,  5), "Buzz", w)
    w = SelectString(mod(p+1, 15), "FizzBuzz", w)
    return w
End

ただこれだけだと,単体テストを知っている方からツッコミが来そうです. 単体テストはコードを改変するたびに実行することが大事で,自動実行できるようにしておくべきなのだ,比較用の関数だけ用意しても意味ないのだ,と.

MinTest.ipfでもテストの一括実行はサポートしていて,どこから行うかというとメニューバーを使います.

f:id:ryotako:20161204143315p:plain

Igor ProはもともとGUIのソフトなのでメニューバー使ってしまうことにしました.で,実行した結果がこちら.

f:id:ryotako:20161204143515p:plain

...失敗しました.テストの結果は履歴エリアに表示されるとともに,メニューバーの表示が変化します. 履歴エリアには期待された値(want),と実際に受け取った値(got)が表示されます.また,メニューバーのjump欄をクリックすると,テストコードの失敗した箇所にジャンプできます*2

hello_world()関数を修正してテストをパスするとこうなります.

f:id:ryotako:20161204144247p:plain

おわりに

テスト便利です.いちいちテスト書くの面倒そう...と思ってましたが,コード修正後の安心感は非常に大きいです. Igor Proはデータ解析用ソフトなので,関数にバグが有ると図らずもデータを歪めてしまうことになります. 学術分野で使われるコードにこそ,テストが必要な気がします.

余談

フィボナッチ数列の実装を見るとIgor Proがすごくデキる子に見える.代入がそのままmapなのが強力.

当然ですが代入をMultiThreadにして高速化しようとすると失敗します.

Function/WAVE fibonacci(n)
    Variable n
    Make/FREE/N=(n) w = 1
    MultiThread w[2,inf] = w[p-1] + w[p-2]
    return w // -> {1,1,2,2,4, ...}
End

*1:Igor Proの内蔵エディタの編集機能は乏しいので,できるだけ短い名前にしました.

*2:Igor Pro 6だと内臓エディタが行番号を表示できないので地味に便利.