- Cpputestに関する情報が英語しかない読みたくない
- CppuMockに可能性を感じるけど、日本語記事がない。
Cpputestを使って単体テストを構築しようと思っているエンジニアいませんか?
情報が英語しかなくて困ったことないでしょうか?
私自身組み込みエンジニアとしてメーカで仕事しており、CppuMockの情報があまりなくて、使いたいけど使えないものになっていたのが正直なところです。
世の中に同じように使いたいけど一歩踏み込めない人が多くいると思い記事にしようと思いました。
今回の記事は、CpputestにおけるCppumockの使い方がわかるまでを目標にしたいと思います
この記事とソースコードをコピペすることで、CppuMockが動いているところを手元で確認するということを目指したいと思います
用語の整理:スタブ?モック?フェイク?
- スタブ:入力に従い一定の出力をするもの
- モック:ある入力に従い期待値を返すもの
- フェイク:使用するデータが本物とは異なるもの
- ダミー:コンパイルエラー対策のような名前だけのもの
結論として、用語は多いですが、同じようなイメージで現場で使う場合が多いです。相手も理解できているかどうかも不明なので、念のため用語の理解を合わせることが大事です。
CppMockのサンプル
- どんなものをコールするか
- 入力値と期待値の書き方
Cpputestが動作することを前提に進めていくので、インストールしていない場合はこちらの記事を参考に入れてください。(記事は後日作成)
CppuMockの説明は以下のサイトに書かれています。cpputest.github.io
さて本題に入っていきます。
まず前提として、
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MockSupport.h"
をした状態にして、チェックしたい関数を作っていきます
今回CheckKeyという関数を例として出します。
レジスターの値を見て、Keyが押されたかどうか読み取るプログラムです
HAL_GPIO_Readがハードウェアに近い関数のため、置き換えないとテストをすることができません。狙った挙動で動かす必要があります。
const int port=1; const int pin =2; int check_key() { int i1,i2,i3; i1 = HAL_GPIO_Read(port, pin); i2 = HAL_GPIO_Read(port, pin); i3 = HAL_GPIO_Read(port, pin); if (i1 && i2 && i3) { return 1; } else { return 0; } }
次にHAL_GPIO_Readを作っていきます。CppuMockを使用することで、
関数が呼ばれたとき、もらったインプットの定義、期待値の出力といった型が既に提供されています。
mock().XXXに必要な項目を書いていきましょう
int HAL_GPIO_Read(int port, int pin){ mock().actualCall("HAL_GPIO_Read") .withIntParameter("port", port) .withIntParameter("pin", pin); return mock().intReturnValue(); }
CppuMockを使用しない場合でも同じようにパラメータをどうするか、返り値をどうするかといった部分は作る必要がありますが、CppuMockによって簡単にできるようになっていますので、使わない手がないですね。
次にテストコードです
TestDownというテスト後の後処理を行う部分に、mock().clearを入れましょう
これを入れないとテスト1,テスト2を実施したときに悪影響を与え、期待通りの結果になりません。
TEST_GROUP(TestGroup1) { void teardown() { mock().clear(); } }; TEST(TestGroup1, Test1) { int ret; mock().expectOneCall("HAL_GPIO_Read") .withIntParameter("port", 1) .withIntParameter("pin", 2) .andReturnValue(1); mock().expectOneCall("HAL_GPIO_Read") .withIntParameter("port", 1) .withIntParameter("pin", 2) .andReturnValue(1); mock().expectOneCall("HAL_GPIO_Read") .withIntParameter("port", 1) .withIntParameter("pin", 2) .andReturnValue(1); ret = check_key(); CHECK_EQUAL(1, ret); }
テストコードを書く際重要なことは下記です
mock().expectOneCall("HAL_GPIO_Read") .withIntParameter("port", 1) .withIntParameter("pin", 2) .andReturnValue(1);
expectOneCallは呼び出すMock関数名を入れてください
withIntParameterに必要なインプットを入れてください
andReturnValueに期待する返り値を入れましょう
以上で終了です。テストコードを実行して結果を確認してください
グリーンになればOKです
まとめ
今回CpputestかつCppumockを使う例を紹介しました。
実際に書いたサンプルが非常に少ないため、ググって調べる方が多いと思います。
今後組み込み開発における気づき、まとめなどを徐々に書いていくので、
気になった方はお気に入り登録お願いします。
参考書籍