複数のプラットフォームで稼働するといわれている Google Test とはとんなものでしょうか? 単体テストツールということは存じています。
昔昔、PCはおもちゃで、高価なUNIXワークステーションでソフト開発をしていました。当然一人一台はありません。マシンでの作業の手戻りを少なくするため、単体テストは重要度が高かったです。しかし近年PCは一人2台以上、クロスプラットフォーム、OSシュミレータ等々あり、(新人さん以外は)どんどん作って動かした方が効率的ともいえます。
しかし組込みソフトは、基板が未だできていない場合、基板が全員分無い、実行時間と人の時間の差が大きく、実機リソースも小さいため、実全てのパスを通しそれを確認することが難しい。そこで自動車業界では、WinAMS がよく使われます。PC上でマイコンレスでコードレベルの検証を行うものです。GUI上で引数を指定して関数単位で実行しカバレッジを収集します。テスト項目の自動生成もある程度できていたかと思います。しかしとても高価です。
もちろんUNIX系でGUI無し以外では、このような場合 Google Test (以降 gtest と呼びます)の出番なのかと。GUI無しぱっと試した感じ以下のようでした。
・テスト項目を自動生成するものではない。自動テストをするものではない。
テスト項目や条件、実行は人が行う必要があります。
・テストに必要な機構と部品がまとまったもの。
いわゆるドライバ、スタブ(モック)の標準機構といえそうです。デバック用に関数の呼出しと結果判定、スタブの呼出しと切替えのための各種機構と部品がそろっているプラットフォームと言えます。ですから覚えることは色々あるようです。
・サポート言語はC / C++
C++ は gtest に合わせて少し直しが必要そうです。
・自分でビルドする必要がある。
基本は git-hub から落としてビルドする必要があります。テスト対象との結合方式は ライブラリ( XXXX.a もしくは XXXX.lib )。うまくできてたか心配になります。
・GUIモノに適用できるのかよくわからない。
基本結果はコンソール出力です。GUIアプリにマージできなくもないとは思いますが、イベントドリブン的な感じではなさそうです。
・Visual Stdioにも何故か含まれていた。
Visual Stdio 2019でも含まれていました。この場合はWindows上から直接実行できます。しかし2018くらいのバージョンの模様です。
Visual Stdio 2019でということで以下試した結果です。いつものプロジェクト作成から選べました。
スタテックリンクするかdllか聞いてきます。
しかしスタブ(モック)機構が Visual Stdio 2019 は入っていないので、NuGetからパッケージを入れます。mockとのネーミングとなっていますが、gtest 本体も含まれています。
インクルードとlibパスは手動で追加します。gtestのみのパッケージ、プロジェクトフォルダ\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.4 は参照しないようrenameしておく。
実際のコードです。Performance クラス の Acceleration メソッドのテストにて、Acceleration 内て呼び出している Parameter クラスの Speedメソッド と Weightメソッドを、テスト用に固定値を返すようにしたものです。クラス図を以下に示します。
コードは以下に示します。説明はコメントをみてください。
test_main.cpp:
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "test_class.h"
#include "Mock_class.h"
using namespace std;
using ::testing::Return; // WillOnce用、必須
using ::testing::_; // 引数用WillOnce用、必須
Performance cars; // テスト対象のクラス
TEST(デフォルト値, Test1) {
EXPECT_EQ(180000, cars.Acceleration());
EXPECT_TRUE(true);
}
TEST(値変更パターン2, Test2) {
// Newでmockインスタンス確保
MockParameter *mock_para1 = new MockParameter() ;
// Performance内で呼出すメソッドのmockを登録。
EXPECT_CALL(*mock_para1, Speed())
.WillOnce(Return(100));
EXPECT_CALL( *mock_para1, Weight() )
.WillOnce(Return(50));
cars.MyPara = mock_para1; // モックをテスト対象クラスに渡す
EXPECT_EQ(5000, cars.Acceleration());
EXPECT_TRUE(true);
delete mock_para1; // vsではないとおこられる
}
TEST(値変更パターン3, Test3) {
// mockインスタンス宣言で確保
MockParameter mock_para2;
// Performance内で呼出すメソッドのmockを登録。
EXPECT_CALL( mock_para2, Speed())
.WillOnce(Return(50));
EXPECT_CALL( mock_para2, Weight() )
.WillOnce(Return(40));
cars.MyPara = &mock_para2;
EXPECT_EQ(2000, cars.Acceleration());
EXPECT_TRUE(true);
}
test_class.h:
#pragma once
#include "gtest/gtest.h"
#include "gmock/gmock.h"
class Parameter {
public:
virtual ~Parameter() {};
// テストでMOCK化メソッド に vitual を付与する。無い場合、
// 実行時:"Actual function call count doesn't match EXPECT_CALL"
// が出る。
virtual int Speed(void) ;
virtual int Weight(void);
};
class Performance {
public:
Performance() {
MyPara = new Parameter(); // 初期値は本物のクラス
}
int Acceleration(void) ;
Parameter *MyPara;
};
test_class.cpp:
#include "test_class.h"
using namespace std;
int Performance::Acceleration(void)
{
cout << "Acceleration in." << endl;
return MyPara->Speed() * MyPara->Weight();
}
int Parameter::Speed()
{
cout << "Speed() in." << endl;
return 100;
}
int Parameter::Weight()
{
cout << "Weight in." << endl;
return 1800;
}
Mock_class.h:
#pragma once
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "test_class.h"
class MockParameter : public Parameter {
public:
MOCK_METHOD0( Speed, int( ) );
MOCK_METHOD0( Weight, int( ) );
};
以下、実行結果です。
なるほど。UNIXサーバ上でtターミナルでログインして開発していたころを思い出します。
その他 gtest に付随して、カバレッジの取得と、カバレッジのhtmlでのビジュアル表示なども可能です。Mockについては、クラス化が前提となってるのが難点ですが、必ずしも使わなくてもよいです。何分、高価な単体テストツールを投資せずカバレッジがとれるので、組込みソフトの机上デバッグに最適かと。もしも急いで動かしたい方は、ぜひこちらよりご相談ください。