NGから芋づる式にバグが見つかる

ここ最近は論理シミュレーションをしているのだが、

2つのテストから、大量のバグを発見して、一体なんぼほど出てくるんだと思った。

テストの難しさってこういうところにあるんだろうなぁって。


そもそもことの発端は、とあるバグが修正されたこと。

このバグに関連してNGとなっていたテストがOKになったか確認しようと思ったら、相変わらずNGだった。

ただ、NGの出る場所が変わっていたので、新しく発生したNGの原因を探ることにしたのだが……

  1. 直接のNG要因はテスト条件の誤りだが、その場合の期待値とは一致しない
  2. その前に実行していたテストでおかしな値が格納されていることが発覚
  3. 1を修正するついでに、2を洗い出せるテストに修正すると、2の要因でNG
  4. 仮修正を行い、OKとなることを確認

というわけで、テスト条件の誤りをきっかけにして詳細を調べたら、別の問題もありそうだとわかって、

その問題を顕在化させるテストに書き換えたら、予想通り発生したわけですね。


ここまでなら大した話ではなかったのだが、上記4.の修正を行ったことで別のバグも直ったのでは? と予想した。

起きている現象はやや異なるが、結果として同じ修正で直りそうだと考えたのだ。

でも、実際にはこれだけでは直らなかったし、さらなるバグがどんどん発見されたのだ。

  1. テストにかかる時間が長すぎるので、リセットを省略するよう修正
  2. その上で実行すると、当初発見したバグAは直っていないし、別の要因でも期待値とずれてNG
  3. 想定とやや異なる波形なので、調査すると 既存製品のバグA’ と 新規バグBの複合で発生したことが発覚
    2.で発生したバグA’を再現するテストを作って既存製品の環境で動かすとNG
  4. 3.以外にも期待値とずれているところがあるので調査すると、エラー発生後に異常な挙動が発生するバグCを発見
    1.のリセット省略の結果、顕在化したことがわかった
  5. バグA’を修正して改めて実行すると、バグB, バグCのNGだけ残る
  6. 5.の結果を見て、エラーレジスタのビット定義に不足があることに気づく(これは保留中)
  7. バグBの原因を調べると、本プロジェクト初期に行った設計に抜けがあることが発覚
  8. 7.の解析結果よりバグBを修正
    4.の解析結果よりある種のソフトリセット処理を追加すればバグCは回避出来るので追加
    これによりバグCは棚上げしてテストOK

と、1つのテストでバグA’,B,Cの3つのバグを顕在化させたのだった。

さらに6.に書いたように仕様上の懸念も発見した。実際にはこれでOKな可能性もあるのだが、要確認だなと。


実は上のテストは当初OKだったらしい。ところが後に通すとNGになってしまったのだ。

上記のバグA,B,Cはいずれも新たに埋め込まれたバグではなく、テストOKの時点から存在していたのだが顕在化しなかっただけなのだ。

実はバグBは他のバグとの組み合わせにより、顕在化してなかったらしいんだよね。

そのバグが修正されたことで、バグBが顕在化した。さらに既存製品から存在したバグA’が顕在化した。

さらにテスト時間短縮のためにリセットを省略する変更を行ったらバグCが顕在化した。

実はもともとテストごとに通電時相当のリセット処理をするという非現実的なことをやってたんだよね。

非現実的だし、通電時相当のリセットは所要時間も長いから、こんなの消してしまえと消した。その結果がこれである。

発生条件を調べたところ、実際にそういう状態に陥ったら、ソフトリセットを叩くだろうし、そのソフトリセットにより復帰出来ることもわかった。

本来はリセットなしで復帰出来るように修正すべきだが、とりあえずは現実に合わせてソフトリセットで復帰するという想定に書き直したのだった。


バグが存在していても、それを顕在化させられるかというと、これは難しい。

操作AでエラーXを発生→操作Bを行うとバグが顕在化する というのはよくあるけど、

これを再現するには、操作A→操作Bを行った上で、なおかつ操作Aでエラーを発生させなければならない。

実機でガチャガチャと動かしていて、操作AでエラーXを起こせるなら発見できる可能性もあるのだが……

実は今回、シミュレーションで起こしたエラーというのは、実機で起こすのは極めて難しい。

なので既存製品でも発見されなかったという実情がある。論理シミュレーションで顕在化させなけば発見しようもないと。


実はそういう観点で言うと、バグCはよくシミュレーションで顕在化できたなと思うのだ。

操作Aの準備→操作AでエラーXを発生→エラーレジスタの確認→(リセット操作)→操作Aの準備(リセットを消すとここでバグが顕在化)

まず、エラーXが発生して、エラーレジスタに正しく格納されることを確認するところで終わってはバグが顕在化することは決してない。

このテストでは、パラメータを変えながら操作Aを繰り返し行うテストなので、顕在化させる余地があったのだが、

通常、操作Aの準備には、エラーを顕在化させる操作はやらないんだよね。

ユースケースに従ってテストを書くと、おそらくこんなテストにはならない。

でも、この変なテストのおかげで、リセット操作を消すだけでバグが顕在化できたのだ。

ただし、エラーXの後に、エラーを顕在化させる操作を行わない保証はないので、これはバグではないと強弁することはできない。


あと、テスト条件の誤りをきっかけとして発見されるバグもけっこう多いんだよね。

期待値が不一致となる直接の原因はテスト条件の誤りだが、そうすると別の矛盾が発見され、掘っていくとバグが見つかることもある。

結論から言えば、テスト条件が不足しているということになる。

テスト条件の誤りをきっかけに追加したテストはけっこうある。

過去に作られたテストを実行してOKとなると、それで満足してしまうけど、

NGになると、何がおかしいか詳しく調べるから、矛盾や不足に気づいちゃうんだよね。

そう考えるとOKとなったテストの裏には潜在的なバグがあるのかもしれないが……まぁ優先度は落ちちゃうよね。