単体テストの時間はしっかり確保しようという話

今日の夕食は煮干しラーメン。

と、いつものように食べ物のことを書くかと思わせつつ、今日は仕事のお話。

今自分は、モジュールデザイン仕様書を元に単体テスト仕様書を作成する
業務を行っているのだが、その作業中、中々力の抜ける出来事があったので
それを書いてみたいと思う。

まず前提としてこの作業、一からテスト項目を作成するわけではない。
別プロジェクトからソースを流用、改変して使用しているため
過去のテスト仕様書が残っており、それを元に改変部分のテスト項目を
追加していく形で作成することになっていたのである。

では、過去にテスト実施済みの、改変されていない既存ソース部分は
テスト不要かと思いきや、そこも再テストする必要があるとのこと。
コンパイラが変更されるためらしい。
なので、全体を見直しつつ追加作業を行っていくことになった。

で、問題はここから。
以下のような処理があった。

 

#define SET_OK 0x01
#define SET_NG 0x02

u_char ub_value;

ub_value = [現在のステータス(2bit)];
if([処理成功か])
{
    /* 成功 */
    ub_value = ub_value | SET_OK;
}
else
{
    /* 失敗 */
    ub_value = ub_value | SET_NG;
}

現在のステータスには0~3が設定されているわけだが、

どの値であろうともor演算の結果、
ub_valueは成功時1か3、失敗時2か3が設定されるはず。

しかし、既存のテスト仕様書には成功時0か1、失敗時0か2が
設定されるように記載されていた。どうもand演算と間違えた模様。
これだけならただの誤記なのだが、なんとテスト結果にはOKと記載されていた。

…実際に動かして、記載通りの結果になったと?
そんなわけあるか。そんなわけあるか。大事なことなので2回言いました。

念のためデバッグ実行で値を確認してみたが、やはり記載通りにはならなかった。

他にも、以下のような処理があった。

 

#define MASK_8BIT 0xff

u_char aubW_data[4];
u_long ulData;

ulData = [32bit数値];
aubW_data[0] = (u_char)(ulData & MASK_8BIT);
aubW_data[1] = (u_char)((ulData >> 8) & MASK_8BIT);
aubW_data[2] = (u_char)((ulData >> 16) & MASK_8BIT);
aubW_data[3] = (u_char)((ulData >> 32) & MASK_8BIT);

単純なシフト演算処理であり、例えばulDataに「0x12345678」が設定された場合、
aubW_dataには[0]から順番に「0x78」「0x56」「0x34」「0x12」が格納されることになる。

しかし、既存のテスト仕様書には「0x12」「0x34」「0x56」「0x78」の順番で
格納されるよう記載されていた。そして例によって結果はOK。

(ノ`Д´)ノ ┫:・’∵:.┻┻:・’.:∵

なぜこんな事になっているのかというと、作成時デスマーチだったらしく、
テスト実施が単体テスト仕様書を作成しながらになっていたらしい。
なので基本的に全てOK記載になり、誤記に気付かないとこんなことになる、と。

流石に単体テストの意味が無いのではと思ったが、最悪結合テストで拾えるからという
苦肉の策だったようだ。まあデスマーチ中に余裕が無くなるのは分からなくもないのだが。

なんにせよ、テストの時間を削って良いはずもない。これを教訓として
テスト時間はしっかり確保しておきたいと思った。

以上