少し前の話ですが、レガシーコード改善勉強会というイベントで登壇させていただきました。
内容としては、自分の組み込みと少し離れた場ということもあり、普遍的なレガシーコードとの扱い方について話させて頂きました。
当日は他の講演もバリエーション豊かで、学ぶものの多い有意義な時間となりました。
登壇を誘っていただいた有地さん、運営者、登壇者、参加者の方々、改めてありがとうございました。
少し前の話ですが、レガシーコード改善勉強会というイベントで登壇させていただきました。
内容としては、自分の組み込みと少し離れた場ということもあり、普遍的なレガシーコードとの扱い方について話させて頂きました。
当日は他の講演もバリエーション豊かで、学ぶものの多い有意義な時間となりました。
登壇を誘っていただいた有地さん、運営者、登壇者、参加者の方々、改めてありがとうございました。
発売は年末となりますが、システムテスト自動化標準ガイド(原題Software Test Automation)という書籍を、有志の仲間で翻訳させていただきました。
Amazon.co.jp: システムテスト自動化 標準ガイド (CodeZine BOOKS): Mark Fewster, Dorothy Graham, テスト自動化研究会: 本
自分は主にメトリクスの章が担当です。
少し古い本ですが、プロセスや管理について有益な内容がよくまとまった本だと思っています。
手にとっていただけると幸いです。
前ブログに続きますがソフトウェア品質シンポジウムにて、Concolic TestingのSIGのサブリーダーを担当させていただきました。
SIGでは色々と技術的な課題が指摘されましたが、研究会としてそれらの対応策を検討していければと考えています。
参加者の方々、大変有難うございました。ソフトウェア品質シンポジウムにてConcolic TestingのSIGを開催
先日、ソフトウェア品質シンポジウムにて、「レビューとテストは使い分けるべきか?」のパネルディスカッションにパネラーとして参加させていただきました。
http://www.juse.jp/sqip/symposium/detail/day2/#session_d4
レポートは後ほど出てくるかと思います。
セッション中の議論も楽しく、有意義な時間となりました。
誘っていただいた細谷さんを始め、参加者の方々、パネリストの方々、大変有難うございました。
少し前の話になりますが、先日WACATE2014夏というソフトウェアテストの合宿勉強会にて、テストに関わるワークショップを担当させていただきました。
テーマは、テスト設計を対象とした、リバースエンジニアリング、追加変更、保守性改善の3つで構成しています。具体的には、問題を抱えるテスト手順書と仕様書を用いて、以下を実施頂きました。
(WACATEではよくありますが)ワークショップでは参加者の方々に想定外の優れたアプローチを構築頂き、モデレータ側としても、学ぶ所が多い有意義な場となりました。
解説資料以外の資料についてはまだオープンにしていませんが、機会があれば公開できればと考えています。
実行委員・参加者の方々には改めてお礼申し上げます。
CRESTは、デフォルトでは解析対象を実行する際に生成した値を出力しない。
生成値を出力する方法としては、公式サイトにて、run_crest本体のコードに細工する方法が以下で説明されている。
https://github.com/jburnim/crest/wiki/CREST-Frequently-Asked-Questions#does-crest-save-the-test-inputs-it-generates
ただ上記の場合、一回のイテレーションで生成する値がすべて0だった場合、値が保存されないようになっている。0とそれ以外での挙動の差異は、CRESTを使ってテスト設計からテスト実行まで自動化しようとする際に注意がいる。
原因として、コードを見ると、解析処理を行うSearch::RunProgram()にて、生成値を格納した引数inputsのサイズが0だと、生成する値をすべて0に初期化する処理を行っているようだ。そして調べて見る限り、CRESTは解析ですべての生成値が0だった場合、inputsをサイズ0のままにしてSearch::RunProgram()を実行し、生成値を初期化している。
そのため対策だけど、「記録された生成値ファイルが空であれば、生成値はすべて0にする」と判断すれば一応支障はなさそうだ。
一方0以外の時と同じように値を記録する際は、ソースコードでのSearch::WriteInputToFileOrDie()に細工が必要になる。例えば生成対象の変数が1つだけなら、以下の様な細工をすると生成値が0かどうかで場合分けが不要になる。
void Search::WriteInputToFileOrDie(const string& file, const vector<value_t>& input) { FILE* f = fopen(file.c_str(), "w"); if (!f) { fprintf(stderr, "Failed to open %s.\n", file.c_str()); perror("Error: "); exit(-1); } for (size_t i = 0; i < input.size(); i++) { fprintf(f, "%lld\n", input[i]); } if (input.size() == 0) { fprintf(f, "0\n"); } fclose(f); }
ただ、そもそも上記の公式の方法では、生成値の型や変数名といった構文情報が失われる。生成値を記録する際は、マクロのCREST_*()に細工して、解析対象から直接生成値を出力させたほうが都合が良いかもしれない。
ちょっと前に、C言語向けConcolic TestingツールであるCRESTを簡易的なサンプルで試したので、結果を簡単にまとめたいと思う。
なおCRESTを使用した雑感は以下の通り:
全体として、動的ユニットテストを用途に限ると、リグレッションテスト以外ではCRESTは使いにくい(テストオラクル問題を何とかしなければならない点と、コードベースである点などから)。そこを使えるようにするには独自のツールサポートやDbCの導入などが必要そう。ただ動的解析としては役に立つ用途がいくつかある。これについてはいずれ出せればと思う。
int hoge(int a) { CREST_int(a); if (a == 1) { return 1; } return 0; }
Read 2 branches. Read 11 nodes. Wrote 0 branch edges.
Iteration 0 (0s): covered 0 branches [0 reach funs, 0 reach branches]. Iteration 1 (0s): covered 1 branches [1 reach funs, 2 reach branches]. Iteration 2 (0s): covered 2 branches [1 reach funs, 2 reach branches].
単純な例でもあり、パスを網羅している。
int hoge(int a) { CREST_int(a); switch (a) { case 0: return 1; case 1: return 2; default: return -1; } return 0; }
Read 6 branches. Read 22 nodes. Wrote 3 branch edges.
ビルドして解析を行っているので、次のマクロ関数のサンプル含め網羅的にパスをピックアップできている。run_crestでもパスを全網羅している
#define FUGA(a) ((a==1) ? 1 : 0) int hoge(int a) { CREST_int(a); int b = FUGA(a); return (FUGA(b)); }
Read 4 branches. Read 13 nodes. Wrote 4 branch edges.
CRESTの仕様上、プリプロセッサを実行したあとのコードを網羅している。
int hoge(int a) { int i; CREST_int(a); for (i = 0; i < a; i++) { if (a < 100) { return 0; } } return 1; }
Read 2 branches. Read 12 nodes. Wrote 1 branch edges.
int hoge(int a) { int b; CREST_int(a); if (a == 0) { return 1; } b = hoge(a - 1); return a * b; }
Read 4 branches. Read 19 nodes. Wrote 4 branch edges.
int hoge(int a) { CREST_int(a); srand((unsigned int)time(NULL)); if ((rand() % a) == 0) { return 0; } return 1; }
Read 2 branches. Read 11 nodes. Wrote 0 branch edges.
Iteration 0 (0s): covered 0 branches [0 reach funs, 0 reach branches]. Floating point exception (core dumped) Iteration 1 (0s): covered 1 branches [1 reach funs, 2 reach branches].
当然かも知れないがrun_crestの実行結果は不安定。rand()のようなテスト対象外の外部コンポーネントはTest Double化が必要になる。