« プロ野球キャンプとテスト工程 | トップページ | C言語における単体テスト テスタビリティを重視した関数設計 »

C言語における単体テスト、あるいはTDDについての考察

今日はあったかかった。というか昼間は暑かった。

==

単体テストといえばjavaのためのJUnitが有名だが、C言語でもCUnitCUnit for Mr.AndoEmbeddedUnitCCUnitなどいくつか世の中に出回っている。

C言語におけるTDDの問題点と解決方法

(1) スタブと実体の競合
他の関数をテストするために作成したスタブと、関数の実体が競合を起こします。

(中略)

(2)スタブ同士の競合
テスト対象の関数に応じたスタブを作成した場合にスタブ同士が競合を起こします。

ここではスタブの競合という問題を、関数の別名宣言、関数ポインタの設定などの手順を使って回避しています。あるいはコンパイル環境を分ける、という解決法も示されています。

これって、ボトムアップの単体・結合テストを繰り返すことでも回避できるんじゃないかと思ってるんだけど、どうなんだろう。最下部のコンポーネント(C言語であれば、システムコール標準関数にあたるか)については単体テスト実施済みというスタンスをとれば、ボトムアップの結合テストを繰り返していけば、すべてのコンポーネント(C言語であれば、ユーザ関数)の単体テストとみなせるのでは?という考え方。

実際に僕がやっている単体テストってこのやり方なのだ。正確には単体テストの進捗具合によって単体(コンポーネント)の単位が大きくなっていくので、見方によっては結合テストともとれるか。

詳細についてはいずれまた。今日はこれくらいで。


|

« プロ野球キャンプとテスト工程 | トップページ | C言語における単体テスト テスタビリティを重視した関数設計 »

コメント

こんばんは。細谷です。
CUnitのテストコードを単体テストと見た場合、書いてくださっている通り、ボトムアップの単体テスト、結合テストを繰り返すことで問題ないと思います。
Kent Beckが著書で述べている「TDD」のテストコードは単体テストというよりは「最後の設計を具現化したもの」という位置づけであり、「テスト駆動開発入門」の中でも実装段階でクラスを追加したり、既に実装済みのクラスを消してしまったり、という様子が書かれています。
このようなダイナミックなリファクタリングを行いながらの開発ではまず全てのテストが容易に実行可能である必要があります。
また、TDDのテストコードは「今、自分が考えなければいけない範囲」を規定する意味もあります。この範囲を狭めて集中することによって誤りが減るということが主張されています。
範囲を狭める上では、スタブを用いて他の関数の実装に影響を受けないテストとする必要があると考えています。
この辺のテストの位置づけに対する考え方は以下にもまとめて
います。
http://hosotani.blog.bai.ne.jp/?eid=82889

最近は、テスト駆動開発の「テスト」という言葉が誤解を生むと言われていて「振る舞い駆動(BDD)」という呼び方にしようという動きがあるようです。

投稿: 細谷 | 2007年3月 4日 (日) 22:41

ウチでもC言語開発でTDDを実施していますが、ボトムアップではなくて、フルでスタビングしています。
ボトムアップでは、IOエラーなどをシミュレートするのが困難ですし、実リソースを隠蔽してテストしたりすのが難しいため、単体テストとしての効果を十分に得られないと考えているためです。
また、コンパイル単位やスタブ単位ではなく、モジュール単位にコンパイル環境を分けて居ます。スタブは固定動作ではなく、複数のテスト項目で異なる動作が出来るように、柔軟に外部から動作をチューニングするインタフェースを(スタブユニットに)持たせています。そういうスタブユニットを一々手で作るのは大変なので、独自のスタブジェネレータを作成して、スタブを実装する必要性をほとんど無くし、生産性をキープしています。
ちなみに、流通しているCUnitの類いは、動的にテスト検出できないものが多いので、テスト検出を動的に行えるように単体テストフレームワーク自体も独自のものを作成しいてます。
結果として、テスティングフレームワークをきちんと作れば、C言語でもオブジェクト指向言語と比べて遜色無い効率でTDDできると感じています(そりゃOOPLの方がネイティブに楽でしょうけど、泣き言も言っていられないので...)。

投稿: geo | 2007年3月 5日 (月) 00:26

>細谷さん

コメントありがとうございます。
URLにある資料、読ませていただきました。

今僕がやっている手法は、資料のp10にあるように
レビュー/カバレッジ測定を織り交ぜてはいますが、
ご指摘の通りロジック部分に特化した単体テストと
捉えたほうが正確かもしれません。

> また、TDDのテストコードは「今、自分が考えなけれ
> ばいけない範囲」を規定する意味もあります。この
> 範囲を狭めて集中することによって誤りが減るとい
> うことが主張されています。
> 範囲を狭める上では、スタブを用いて他の関数の実装
> に影響を受けないテストとする必要があると考えて
> います。

「範囲を狭めて誤りを減らす」ためにはやはり他の
ユニットとの独立性が必要なんでしょうか。
自分の感覚的なイメージで他のユニットでも一定の
レベルの保証がされていれば独立性が保てるのかと
認識していました。


投稿: softest | 2007年3月 5日 (月) 11:57

>geoさん

いつもコメントありがとうございます。
I/Oエラーやメモリエラーなどのシミュレートはご指摘
の通り悩みのタネです。力技でコードを書き換えて
エラー発生させたりしていますが、これが正しいのかも
自分ではぼんやりしています。。

僕のやり方だと、複数の動作をさせるためのスタブや
それらを生成するスタブジェネレータをボトムアップ
な結合で実現しようとしている感じですね。
(まあ、それがご指摘の通り新たな悩みを生んでますが)


投稿: softest | 2007年3月 5日 (月) 12:04

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/155415/5331669

この記事へのトラックバック一覧です: C言語における単体テスト、あるいはTDDについての考察:

« プロ野球キャンプとテスト工程 | トップページ | C言語における単体テスト テスタビリティを重視した関数設計 »