CppUTestは、組み込み C 開発に最適です。これは、無料の関数をモックできる唯一のテスト フレームワークであるためです (この場合はwrite_to_i2c()
とread_from_i2c()
)。
ここで、CppUTest のドキュメントまたは優れた本Test Driven Development for Embedded Cを実際に読んでいる必要があります。
とにかく、次のコードはそれを行う方法を示しています。
コンパイル可能な方法で書かれたテスト対象ユニット (UUT) (次に SO で質問するときは、努力してください):
#include "temperature.h"
#include "i2c.h"
void somethingA(void) { }
void somethingB(void) { }
void temperature_do(uint8_t address, uint8_t value) {
write_to_i2c(address, value);
const uint8_t tempReadback = read_from_i2c(address);
if (tempReadback == value) {
somethingA();
} else {
somethingB();
}
}
あなたが書いたように、「偽造」する必要があります。より正確には「モック」する必要がwrite_to_i2c()
ありread_from_i2c()
ます。モックを別のファイル (i2c_mock.cpp など) に入れて、単体テストをビルドするときに、実際の実装ではなくモックに対してリンクするようにします。
extern "C" {
#include "i2c.h"
};
#include "CppUTestExt/MockSupport.h"
void write_to_i2c(uint8_t address, uint8_t value) {
mock().actualCall(__FUNCTION__)
.withParameter("address", address)
.withParameter("value", value);
}
uint8_t read_from_i2c(uint8_t address) {
mock().actualCall(__FUNCTION__)
.withParameter("address", address);
uint8_t ret = mock().returnIntValueOrDefault(0);
return ret;
}
詳細については、CppUMock のドキュメントを参照してください。これは単なる古典的な CppUMock ボイラープレートです。
最後の部分は単体テストです。
extern "C" {
#include "temperature.h" // UUT
};
#include "CppUTest/TestHarness.h"
#include "CppUTest/CommandLineTestRunner.h"
#include "CppUTestExt/MockSupport.h"
TEST_GROUP(Temperature)
{
void setup() {}
void teardown() {
mock().checkExpectations();
mock().clear();
}
};
TEST(Temperature, somethingA)
{
const uint8_t value = 10;
mock().ignoreOtherCalls();
mock().expectOneCall("read_from_i2c").ignoreOtherParameters()
.andReturnValue(value);
temperature_do(10, value);
}
TEST(Temperature, somethingB)
{
const uint8_t value = 10;
mock().ignoreOtherCalls();
mock().expectOneCall("read_from_i2c").ignoreOtherParameters()
.andReturnValue(value+1);
temperature_do(10, value);
}
int main(int argc, char** argv) {
return CommandLineTestRunner::RunAllTests(argc, argv);
}
この UT は、実際には 100% のブランチ カバレッジを提供します。繰り返しますが、すべての詳細を説明することはできません。somethingA
テスト ケースとを観察して比較するとsomethingB
、UUT が を呼び出すパスに 1 回入り、 を呼び出すパスに 1 回入るには何が必要かがわかりsomethingA()
ますsomethingB()
。
例を挙げましょう
mock().expectOneCall("read_from_i2c")
.ignoreOtherParameters()
.andReturnValue(value+1);
ここで、 CppUmock に function の呼び出しを期待しread_from_i2c()
、パラメータが何であるかを無視し、これは基本的に重要であり、返すvalue + 1
(または とは異なるその他の何か) を返すように言っていますvalue
。これにより、UUT は を呼び出すパスに入りますsomethingB()
。
組み込み C 開発と単体テストをお楽しみください。