【C言語】static(private)関数をユニットテストする3つの方法【単体テストのバッドノウハウ】

前書き:C言語のstatic関数は単体テストできます

C言語で単体テストを作成する際に、「どうやってstatic関数をテストコードから呼び出せばいいのか?」と迷った事はありませんか?例えば、以下のコードのprivate_func()を他のCソースファイル(例:テストコード)から呼び出せるでしょうか。

結論を言えば、static関数を単体テストする方法は3通りあります。本記事では、3通りの方法をそれぞれ紹介します。

static関数を単体テストする方法
  • 単体テストの時だけstatic指定子を消す方法
  • static関数のラッパー関数(public)を作成する方法
  • テスト対象のコードをincludeする方法

                       

単体テストの時だけstatic指定子を消す方法

この方法は、#ifdef/#ifndef、#defineマクロ、gccコンパイルオプションを駆使して、static指定子を単体テスト時のみ消します。本記事で紹介する中で、この方法が最も自然です。

まず、任意のヘッダファイル(private.h)に#defineマクロと#ifdef/#ifndefを使用して、テスト時のみstatic指定子が消えるようにします。以下の例では、__TEST__が定義済みの場合はstatic指定子が消え、static関数がpublic関数として宣言されます。__TEST__が未定義の場合はstatic指定子が残り、pricate_func()関数の宣言はヘッダファイルから消えます。

次に、ソースコード(private.c)では__TEST__が未定義の場合のみ、private_func()関数の宣言をします。このように実装すれば、__TEST__の定義・未定義によって、private_func()の宣言先がヘッダーファイルかソースファイルかが切り替わります。

最後に、テストコード(test.c)を以下のように実装します。

__TEST__の定義は、gccコンパイルオプション(”-Dオプション”)で指定します。以下に実例を示します。

                               

static関数のラッパー関数(public)を作成する方法

この方法は、テスト対象static関数のラッパー関数(public)を作成します。無駄なラッパー関数がソースファイルに含まれるので、あまり好ましくないです。

まず、ソースコード(private.c)では、static関数(private_func)のラッピングする関数(wrapper_private_func)を作成します。

残りの作業は、このラッパー関数の宣言をヘッダーファイル(private.h)に記載し、テストコード(test.c)からラッパー関数を呼び出すだけです。

以下に実行例を示します。

                                                    

テスト対象のコードをincludeする方法

この方法は、# includeを用いて、static関数を定義したソースファイルをテストコードに読み込む方法です。私は、この方法を初めて聞いた時、「頭がいい方法だな」と思わず、「気持ち悪っ!」と嫌悪感を示しました。今でも良く覚えています。

実装方法は簡単で、テストコードを書いたソースファイル(test.c)にテスト対象ファイル(private.c)をincludeするだけです。C言語の#includeは、指定したファイルを#include指定行に展開する仕組みなので、ヘッダーファイル以外(=ソースファイル)も指定できます。

最後に、実行例を示します。

                                

余談:#includeでソースファイルを読み込む実例

coreutilsパッケージで提供されるfalseコマンド(必ず1を返すコマンド)は、#includeでソースファイルを読み込んでいます。以下の記事の下部に、実装解説がありますので、興味がある方は読んでみてください。

/etc/passwdに記載された/usr/sbin/nologin, /bin/falseとは何か【ログイン禁止】

おすすめ

1件の返信

  1. 2020年12月20日

    […] ユニットテストしないコードは複雑になりがちで、バグりやすい。(static関数もテスト可能であり、組み込みでもユニットテストする) […]