私は今年の夏、C言語で書かれた組み込みシステムを開発しました。それは私が働いていた会社が引き継いだ既存のプロジェクトでした。私はJUnitを使ってJavaで単体テストを書くことに慣れてきましたが、既存のコード(リファクタリングを必要とする)のための単体テストを書くための最良の方法やシステムに追加された新しいコードに関しては迷いました。
JUnit のように、単体テストのCコードをJavaコードの単体テストと同じくらい簡単にする方法はありますか?組み込み開発(arm-linuxプラットフォームへのクロスコンパイル)に特に当てはまる洞察は非常に高く評価されます。
Cの一つのユニットテストフレームワークは Check です。 Cの単体テストフレームワークのリストは ここ で見つけることができ、以下に再現されています。ランタイムに標準ライブラリ関数がいくつあるかに応じて、それらのうちの1つを使用できるかどうかが決まります。
AceUnit
AceUnit(アドバンストCおよびエンベデッドユニット)は、快適なCコードユニットテストフレームワークとしての地位を得ています。それはJUnit 4.xを模倣しようとし、リフレクションのような機能を含みます。 AceUnitはリソース制約環境で使用できます。組込みソフトウェアの開発、そして重要なことには、単一の標準ヘッダファイルをインクルードすることができず、ANSI/ISO Cライブラリから単一の標準C関数を呼び出すことができない環境でうまく動作します。 Windowsポートもあります。著者はそのような機能を追加することに興味を表明していますが、それは信号をトラップするためにフォークを使用しません。 AceUnitホームページ を参照してください。
GNU Autounit
Checkと同じ行に沿って、別のアドレス空間で単体テストを実行するのをやめることを含めて(実際、Checkの最初の作者はGNU Autounitからアイデアを借りました)。 GNU AutounitはGLibを広範に使用します。つまり、リンクなどには特別なオプションが必要ですが、特にGTKまたはGLibを既に使用している場合は特に問題にはなりません。 GNU Autounit homepage を参照してください。
cUnit
GLibも使用しますが、単体テストのアドレス空間を保護するためにforkしません。
CUnit
Win32 GUIの実装を計画している標準C。現在、単体テストのアドレス空間をフォークまたは保護していません。開発初期です。 CUnit homepage を参照してください。
CuTest
ソースツリーにドロップする1つの.cファイルと1つの.hファイルを持つ単純なフレームワーク。 CuTestホームページ を参照してください。
CppUnit
C++用の最高のユニットテストフレームワーク。 Cコードをテストするためにそれを使うこともできます。安定しており、積極的に開発されており、GUIインターフェースを備えています。 CppUnitをCに使用しない主な理由は、それが非常に大きいということと、テストをC++で記述しなければならないという2つの理由です。つまり、C++コンパイラが必要です。これらが心配にならない場合は、他のC++単体テストフレームワークと一緒に検討する価値があります。 CppUnitホームページ を参照してください。
embUnit
embUnit(Embedded Unit)は、組み込みシステム用のもう一つのユニットテストフレームワークです。これはAceUnitに取って代わられたようです。 組み込みユニットホームページ 。
MinUnit
最小限のマクロのセットです。ポイントは、コードの単体テストがどれほど簡単かを示すことです。 MinUnitホームページ を参照してください。
安藤さんのCUnit
かなり新しく、明らかにまだ初期の開発段階にあるCUnit実装。 安藤氏ホームページのCUnit を参照してください。
このリストは2008年3月に最後に更新されました。
CMockaはモックオブジェクトをサポートするCのテストフレームワークです。使い方とセットアップは簡単です。
CMockaのホームページ を参照してください。
Criterionは、自動テスト登録、パラメータ化されたテスト、理論をサポートするクロスプラットフォームのC単体テストフレームワークで、TAPやJUnit XMLを含む複数の形式に出力できます。各テストは独自のプロセスで実行されるため、必要に応じてシグナルやクラッシュを報告またはテストできます。
詳しくは Criterion homepage をご覧ください。
HWUTは、Cを非常にサポートする一般的な単体テストツールです。Makefileの作成、最小の「反復テーブル」でコーディングされた大規模なテストケースの生成、ステートマシンをたどる、Cスタブの生成などに役立ちます。一般的なアプローチは非常に独特です。評決は 'good stdout/bad stdout'に基づいています。ただし、比較機能は柔軟です。したがって、どのタイプのスクリプトでもチェックに使用できます。それは標準出力を生成することができるどんな言語にも適用されるかもしれません。
HWUTのホームページ を参照してください。
C、C++用の最新の、移植性のある、クロス言語の単体テストおよびモックフレームワーク。オプションのBDD表記法、モッキングライブラリ、単一のプロセスで実行する機能(デバッグを容易にするための機能)を提供します。テスト機能を自動的に発見するテストランナーが利用可能です。しかし、あなたはプログラム的にあなた自身のものを作ることができます。
これらすべての機能(およびその他)は CGreenマニュアル で説明されています。
ウィキペディアには、 ユニットテストフレームワークのリスト:C の下にCユニットテストフレームワークの詳細なリストがあります。
個人的には Google Test framework が好きです。
Cコードをテストする際の本当の難しさは、外部モジュールへの依存関係を壊して、コードをユニットごとに分離できるようにすることです。これは、レガシーコードに関するテストを取得しようとする場合に特に問題になる可能性があります。この場合、テストでスタブ関数を使用するためにリンカーを使用することがよくあります。
これは、人々が「seams」について話すときに言及しているものです。 Cでの唯一の選択肢は、実際にプリプロセッサまたはリンカを使用して依存関係を模擬することです。
私のCプロジェクトの典型的なテストスイートは次のようになります。
#include "myimplementationfile.c"
#include <gtest/gtest.h>
// Mock out external dependency on mylogger.o
void Logger_log(...){}
TEST(FactorialTest, Zero) {
EXPECT_EQ(1, Factorial(0));
}
実際にはヘッダーファイルではなく、Cファイルが含まれていることに注意してください。これにより、すべての静的データメンバーにアクセスできるという利点があります。ここでは、ロガーをモックアウトします(logger.oにあり、空の実装を提供します。これは、テストファイルがコードベースの残りの部分から独立してコンパイルおよびリンクされ、単独で実行されることを意味します。
コードのクロスコンパイルに関しては、これが機能するためにはターゲットに優れた機能が必要です。 PowerPCアーキテクチャでLinuxにクロスコンパイルされたgoogletestでこれを実行しました。結果を収集するための完全なシェルとOSがあるので、これは理にかなっています。リッチでない環境(完全なOSを持たないものとして分類します)の場合は、ホストでビルドして実行するだけです。ビルドの一部としてテストを自動的に実行できるように、とにかくこれを行う必要があります。
OOコードは一般に手続き型よりも結合度が低いため、C++コードのテストは一般的にはるかに簡単です(もちろん、これはコーディングスタイルに大きく依存します)。また、C++では、依存性注入やメソッドオーバーライドなどのトリックを使用して、カプセル化されたコードに継ぎ目を入れることができます。
Michael Feathersには レガシーコードのテストに関する優れた本 があります。ある章では、私が強くお勧めする非OOコードを扱うためのテクニックについて説明しています。
Edit:プロシージャコードの単体テストについて ソースはGitHubで入手可能ブログ投稿 ==。
Edit: Pragmatic Programmersから出てくる新しい本 があります。これは特に、Cコードの単体テストに対処します 私は強くお勧めします 。
Minunit は、非常に単純な単体テストフレームワークです。私はAVR用のCマイクロコントローラのコードをユニットテストするためにそれを使っています。
私は現在CuTestユニットテストフレームワークを使用しています。
http://cutest.sourceforge.net/ /
非常に軽量でシンプルなので、組み込みシステムに最適です。ターゲットプラットフォームでもデスクトップでも問題なく動作します。単体テストを書くことに加えて、必要なのは以下のとおりです。
システムはヒープといくつかのstdio機能(すべての組み込みシステムが持っているわけではない)をサポートする必要があります。しかし、コードは非常に単純なので、あなたのプラットフォームにそれらがなければ、おそらくこれらの要件に代わるもので作業することができます。
Extern "C" {}ブロックを慎重に使用すれば、C++のテストもサポートされます。
私はratkokとほぼ同じと言っていますが、もしあなたが単体テストに埋め込まれた工夫があれば...
Unity - Cコードを単体テストするための強く推奨されるフレームワーク。
このスレッドの中で言及されている本の中の例は 組み込みCのためのTDD はUnity(およびCppUTest)を使って書かれています。
また、 libtap 、TAP(Test Anything Protocol)を出力し、このテクノロジ用に出てくるさまざまなツールとうまく統合できるCテストフレームワークも検討してください。主に動的言語の世界で使用されていますが、使用が簡単で非常に普及してきています。
例:
#include <tap.h>
int main () {
plan(5);
ok(3 == 3);
is("fnord", "eek", "two different strings not that way?");
ok(3 <= 8732, "%d <= %d", 3, 8732);
like("fnord", "f(yes|no)r*[a-f]$");
cmp_ok(3, ">=", 10);
done_testing();
}
cmocka と呼ばれるモックオブジェクトをサポートするC用のエレガントなユニットテストフレームワークがあります。それは標準的なCライブラリを必要とするだけで、(組み込みを含む)様々なコンピューティングプラットフォーム上でそして異なるコンパイラで動作します。
Subunit、Test Anything Protocol、jUnit XMLレポートなど、さまざまなメッセージ出力フォーマットもサポートしています。
cmockaは組み込みプラットフォームでも動作するように作成されており、Windowsもサポートしています。
簡単なテストは次のようになります。
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
/* A test case that does nothing and succeeds. */
static void null_test_success(void **state) {
(void) state; /* unused */
}
int main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(null_test_success),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
_ api _ は完全に文書化されており、いくつかの例がソースコードの一部です。
Cmockaを使い始めるには、LWN.netの記事を読んでください: Cでのモックオブジェクトを使ったユニットテスト /
cmocka 1.0が2015年2月にリリースされました。
機能をモックする方法を模索するようになるまで、私はレガシーCアプリケーションのテストをそれほど行っていませんでした。テストしたいCファイルを他の人から隔離するには、モックがひどく必要でした。私はcmockを試してみました、そして私はそれを採用すると思います。
Cmockはヘッダーファイルをスキャンし、見つかったプロトタイプに基づいてモック関数を生成します。モックを使用すると、Cファイルを完全に分離してテストできます。テストファイルを実際のオブジェクトファイルではなくモックにリンクするだけです。
Cmockのもう1つの利点は、疑似関数に渡されるパラメータを検証し、疑似関数が提供する戻り値を指定できるようになることです。これはあなたの関数の中で異なる実行フローをテストするのに非常に便利です。
テストは典型的なtestA()、testB()関数で構成されています。そこでは期待値を構築し、アサートをテストしチェックするための関数を呼び出します。
最後のステップは、あなたのテスト用のランナーを統一的に生成することです。 Cmockは結束度テストフレームワークと結びついています。 Unityは他の単体テストフレームワークと同じくらい簡単に習得できます。
試してみる価値があり、非常に簡単に把握できます。
http://sourceforge.net/apps/trac/cmock/wiki
更新1
私が調査しているもう一つのフレームワークはCmockeryです。
http://code.google.com/p/cmockery/ /
それは単体テストとモックをサポートする純粋なCフレームワークです。 Rubyへの依存性はなく(Cmockとは対照的)、外部のライブラリへの依存性はほとんどありません。
それはコード生成をしないのでそれはモックを設定するためにもう少し手作業を必要とします。プロトタイプはそれほど変わらないので、これは既存のプロジェクトのための多くの作業を表すものではありません。余分なタイピングはモックの完全なコントロールを提供します。気に入らないものがある場合は、単にモックを変更するだけです。
特別なテストランナーは必要ありません。テストの配列を作成してそれをrun_tests関数に渡すだけです。ここでももう少し手作業で作業しますが、私は間違いなく自己完結型の自律フレームワークのアイデアが好きです。
それに加えて、私が知らなかった気の利いたCトリックがいくつか含まれています。
全体的なCmockeryを始めるには、モックについてもう少し理解する必要があります。例はあなたがこれを克服するのを助けるべきです。それはそれがより簡単な力学で仕事をすることができるように見えます。
C初心者として、 Cでのテスト駆動開発 というスライドがとても役に立ちました。基本的に、標準のassert()
と&&
を使ってメッセージを配信します。外部の依存関係はありません。誰かがフルスタックテストフレームワークに慣れているなら、これはおそらくしないでしょう:)
私はフレームワークを使いません、私はただautotools「チェック」ターゲットサポートを使います。 「main」を実装してassertを使用します。
私のテストディレクトリのMakefile.amは次のようになります。
check_PROGRAMS = test_oe_amqp
test_oe_amqp_SOURCES = test_oe_amqp.c
test_oe_amqp_LDADD = -L$(top_builddir)/components/common -loecommon
test_oe_amqp_CFLAGS = -I$(top_srcdir)/components/common -static
TESTS = test_oe_amqp
CUnit があります
そして Embedded Unit はEmbedded C System用のユニットテストフレームワークです。その設計はJUnitやCUnitなどからコピーされ、その後Embedded C Systemにいくらか適応しました。 Embedded Unitはstd Cライブラリを必要としません。すべてのオブジェクトはconst領域に割り当てられます。
そして Tessy は組み込みソフトウェアの単体テストを自動化します。
使いやすさと移植性を考慮して、 _ cheat _ ( GitHub でホストされています)と書きました。
依存関係はなく、インストールや設定は不要です。ヘッダファイルとテストケースだけが必要です。
#include <cheat.h>
CHEAT_TEST(mathematics_still_work,
cheat_assert(2 + 2 == 4);
cheat_assert_not(2 + 2 == 5);
)
テストは実行可能ファイルにコンパイルされ、テストを実行してその結果を報告します。
$ gcc -I . tests.c
$ ./a.out
..
---
2 successful of 2 run
SUCCESS
色もきれいです。
Michael Featherの著書「レガシーコードを効果的に活用する」には、C開発中の単体テストに特有の多くのテクニックが記載されています。
私が他では見たことがないCに特有の依存性注入に関連したテクニックがあります。
CppUTest - Cコードを単体テストするための強く推奨されるフレームワーク。
このスレッドで言及されている本の例は 組み込みC用のTDD はCppUTestを使用して書かれています。
私は CxxTest を埋め込みc/c ++環境(主にC++)に使用します。
テストランナーを構築するためのPerl/pythonスクリプトがあるので、CxxTestが好きです。それをセットアップするための小さな傾斜の後(テストランナーを書く必要がないのでまだ小さい)、それは非常に使いやすいです(サンプルと役に立つドキュメントを含みます)。ほとんどの作業は、コードがアクセスする「ハードウェア」を設定することでしたので、ユニット/モジュールテストを効果的に行うことができました。その後、新しいユニットテストケースを追加するのは簡単です。
前述のように、これはC/C++の単体テストフレームワークです。そのため、C++コンパイラが必要になります。
Minunitを読んだ後、もっと良い方法はassertマクロのテストをベースにすることだと思いました。だから私はMinunitの同じ考えを標準的な主張と組み合わせて使った。私のフレームワーク(良い名前はNoMinunitかもしれません)を k0gaのブログで見ることができます
Googleは優れたテストフレームワークを持っています。 https://github.com/google/googletest/blob/master/googletest/docs/primer.md
そして、はい、私の知る限り、それは普通のCで動くでしょう。
cmockery http://code.google.com/p/cmockery/
Cmockery は、単体テストを書くための非常に単純なCライブラリを使用した、最近立ち上げられたプロジェクトです。
まず、ここを見てください: http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#C
私の会社は私達の顧客が使うCライブラリを持っています。コードをテストするためにCxxTest(C++単体テストライブラリ)を使用します。 CppUnitも動作します。あなたがCで立ち往生しているなら、私はRCUNITをお勧めします(しかしCUnitも良いです)。
lcutしてみてください。 - http://code.google.com/p/lcut
API健全性チェッカー - C/C++ライブラリ用のテストフレームワーク:
共有C/C++ライブラリ用の基本単体テストの自動ジェネレータ。パラメータの妥当な(ほとんどの、残念ながら全部ではないが)入力データを生成し、ヘッダ内の宣言を分析することによって、API内のすべての関数について単純な(「健全性」または「浅い」品質)テストケースを作成できますファイル.
生成されたテストの品質により、簡単な使用例で重大なエラーがないことを確認できます。このツールは、生成されたテストを構築して実行し、クラッシュ(セグメンテーション違反)、中止、あらゆる種類の発行されたシグナル、ゼロ以外のプログラム戻りコード、およびプログラムのハングを検出することができます。
例:
_ rcunit _ を使用して、ターゲット上でテストする前に、PC上で組み込みコードの単体テストを実行しました。ハードウェアインタフェースの抽象化が優れていると、エンディアンとメモリマップレジスタが重要になります。
あなたがJUnitに精通しているならば、私はCppUnitを推薦します。 http://cppunit.sourceforge.net/cppunit-wiki
それはあなたがユニットテストをするためのC++コンパイラを持っていると仮定しています。そうでなければ、チェックがあなたが望むものであることを私はアダムローゼンフィールドに同意しなければなりません。
LibU( http://koanlogic.com/libu )には、明示的なテストスイート/ケースの依存関係、テストの分離、並列実行、およびカスタマイズ可能なレポートフォーマッタ(デフォルトの形式はxmlおよびtxt)を可能にする単体テストモジュールがあります。
ライブラリはBSDライセンスされており、他の多くの便利なモジュールが含まれています - ネットワーキング、デバッグ、一般的に使用されるデータ構造、設定など - あなたがあなたのプロジェクトでそれらを必要とすれば...
Cutter(http://cutter.sourceforge.net/) あなたはCとC++をテストすることができます、それはシームレスにautotoolsと統合することができて、本当に素晴らしいチュートリアルが利用可能です。
使用する1つの手法は、ターゲットシステムのソースをCモジュールとして維持しながら、C++ xUnitフレームワーク(およびC++コンパイラ)を使用して単体テストコードを開発することです。
可能であれば、単体テストを使用して、クロスコンパイラの下でCソースを定期的にコンパイルしてください。
まだテストフレームワークを探しているのなら、 CUnitWin32 はWin32/NTプラットフォーム用のものです。
これは私が他のテストフレームワークで直面した一つの根本的な問題を解決します。つまり、各テストは別々のプロセスとして実行されるため、グローバル/スタティック変数は確定的な状態にあります。
Win32プラットフォームまたはNTカーネルモードをターゲットにしている場合は、 cfix を見てください。
私は Libcut を書いたのは、既存のC単体テストライブラリに対するフラストレーションです。プリミティブの自動型文字列(test_eq_int、test_eq_long、test_eq_shortなどは不要です。プリミティブと文字列には異なる2つのセットのみ)が1つのヘッダーファイルで構成されています。これは簡単な例です。
#include <libcut.h>
LIBCUT_TEST(test_abc) {
LIBCUT_TEST_EQ(1, 1);
LIBCUT_TEST_NE(1, 0);
LIBCUT_TEST_STREQ("abc", "abc");
LIBCUT_TEST_STRNE("abc", "def");
}
LIBCUT_MAIN(test_abc);
ただしC11でしか動作しません。