Effizientes und effektives Testen von Embedded SW mit Google Test Michael Bernhard 1
Agenda Warum testen? Wie testen? Google Test und Google Mock Toolintegration Schlussfolgerung 2
Die Norm fordert es Warum testen? Es braucht Sicherheit, dass ein Release genügend stabil und möglichst fehlerfrei ist Regressionen auffinden Debuggen Test-driven development Refactoring 3
Wie testen? Test-Framework Host, Simulator oder Target? Unit Test Was ist ein Unit? Codeabdeckung Testautomation Integration in IDE 4
Google Test Eine Bibliothek zum Schreiben von C++ Tests Open-Source, BSD Lizenz xunit Architektur Portabel und konfigurierbar Einfach zu erlernen, ausdruckstarkes Konzept Erweiterbar 5
Der Building Block cmp Building Blocks BuildingBlock:: Serv ice BuildingBlock «interface» BuildingBlock:: Adapter Adapter Service * BuildingBlock:: InternalClass AdaptedClass 6
Applikation mit Building Blocks cmp Clock SetDisplaState SetDisplaState «BuildingBlock» Controller DisplayTime DisplayTime «buildingblock» Display StartTimer BlinkTimerEvent SecondTick KeyEvent StartBlinkTimer GetBitmap DisplayString DisplayBitmap GetDimension «blocking» KeyEvent StartTimer TimerExpired Start Stop GetBitmap TimerElapsed «BuildingBlock» KeyDecoder «BuildingBlock» Timer «BuildingBlock» ResourceRepository GpioInterrupt KeyInterrupt Start StartTimerTick Stop StopTimerTick TimerTick TimerTick Read Read DisplayString DisplayBitmap GetDimension «driver» GpioDriv er «driver» TimerDriv er «driver» FlashPartition «driver» DisplayDriv er 7
Google Test: Ein kleines Beispiel cmp Building Blocks MMI Serv ice + Setup(AdapterBase&) : void + GetModeSwitch() : Mode + SetPowerLamp(boolean) : void + SetWarnLamp(boolean) : void «interface» AdapterBase + ReadSwitches() : int + SetLamps(int) : void 8
Google Test: Ein Testcase #include "mmi.h" #include <gtest/gtest.h> class AdapterStub : public MMI::AdapterBase public: int ReadSwitches() return 1; } void SetLamps(int state) } }; TEST(MMITest, GetModeSwitch) AdapterStub a; MMI::Service s; s.setup(a); TEST(MMITest, SetPowerLampOn) AdapterStub a; MMI::Service s; s.setup(a); } EXPECT_EQ(MMI::MODE_A, s.getmodeswitch()); } s.setpowerlamp(true); 9
#include "mmi.h" #include <gtest/gtest.h> Google Test: Test-Fixture class AdapterStub : public MMI::AdapterBase public: int ReadSwitches() return 1; } void SetLamps(int state) } }; class MMITest : public ::testing::test protected: void SetUp() s.setup(a); } }; AdapterStub a; MMI::Service s; TEST_F(MMITest, GetModeSwitch) EXPECT_EQ(MMI::MODE_A, s.getmodeswitch()); } TEST_F(MMITest, SetPowerLampOn) s.setpowerlamp(true); } 10
Google Test: Testrunner #include <gtest/gtest.h> int main(int argc, char **argv) testing::initgoogletest(&argc, argv); return RUN_ALL_TESTS(); } 11
Google Test: Test Makros EXPECT vs. ASSERT ASSERT_TRUE(fp = fopen(path, "r")); ASSERT_EQ(10, fread(buffer, 1, 10, fp)); EXPECT_STREQ("123456789", buffer); Zusätzlicher Fehlerbeschrieb ASSERT_TRUE(fp = fopen(path, "r")) << "Failed to open the data file."; ASSERT_EQ(10, fread(buffer, 1, 10, fp)) << "The data file is smaller than expected."; EXPECT_STREQ("123456789", buffer) << "The data file is corrupted."; expect_assert.cpp:24: Failure Value of: (fp = fopen(path, "r")) Actual: false Expected: true Failed to open the data file. 12
Google Test: Predicates bool MutuallyPrime(int m, int n)... } int a = 4, b = 10; EXPECT_TRUE(MutuallyPrime(a, b)); predicate.cpp:11: Failure Value of: MutuallyPrime(a, b) Actual: false Expected: true EXPECT_PRED2(MutuallyPrime, a, b); predicate.cpp:12: Failure MutuallyPrime(a, b) evaluates to false, where a evaluates to 4 b evaluates to 10 13
Der Building Block cmp Building Blocks BuildingBlock:: Serv ice BuildingBlock «interface» BuildingBlock:: Adapter Adapter Service * BuildingBlock:: InternalClass AdaptedClass 14
Stubs, Fakes oder Google Mock? Stubs oder Fakes Notwendig, da das Unit isoliert getestet werden soll Oft verschiedene Implementation notwendig Wie sieht man, was alles zu einem Test gehört? Google Mock Eine Implementation Konfiguration zur Laufzeit direkt im jeweiligen Test Beliebiges Verhalten Verifikation der Funktionsparameter Abhängigkeit der Funktionsaufrufe spezifizierbar 15
Google Mock: Die Mock Klasse class AdapterBase public: virtual int ReadSwitches() = 0; virtual void SetLamps(int state) = 0; }; #include "mmi.h" #include <gmock/gmock.h> class AdapterMock : public MMI::AdapterBase public: MOCK_METHOD0(ReadSwitches, int()); MOCk_METHOD1(SetLamps, void(int)); }; 16
Google Mock: Erwartungen formulieren #include "mmi.h" #include <gmock/gmock.h> using ::testing::return; using ::testing::eq; class MMITest : public ::testing::test protected: TEST_F(MMITest, GetModeSwitch) void SetUp() s.setup(a); EXPECT_CALL(a, ReadSwitches()).WillOnce(Return(1)); } AdapterMock a; EXPECT_EQ(MMI::MODE_A, s.getmodeswitch()); MMI::Service s; } }; TEST_F(MMITest, SetPowerLampOn) EXPECT_CALL(a, SetLamps(Eq(1))); } s.setpowerlamp(true); 17
Google Mock: Fehlerbeschrieb TEST_F(MMITest, SetPowerLampOn) EXPECT_CALL(a, SetLamps(Eq(1))); } s.setpowerlamp(true); Unexpected mock function call - returning directly. Function call: SetLamps(4) Google Mock tried the following 1 expectation, but it didn't match: mmi_test.cpp:34: EXPECT_CALL(a, SetLamps(Eq(1)))... Expected arg #0: is equal to 1 Actual: 4 Expected: to be called once Actual: never called - unsatisfied and active mmi_test.cpp:34: Failure Actual function call count doesn't match EXPECT_CALL(a, SetLamps(Eq(1)))... Expected: to be called once Actual: never called - unsatisfied and active 18
Eclipse Error Marker bei Fehler Unit Test Support in CDT Toolintegration 19
Toolintegration: Eclipse 20
Eclipse Error Marker bei Fehler Unit Test Support in CDT Toolintegration Einfaches Debuggen (--gtest_break_on_failure) Hudson/Jenkins Integration via XML Ausgabe 21
Toolintegration: Hudson/Jenkins 22
Eclipse Error Marker bei Fehler Unit Test Support in CDT Toolintegration Einfaches Debuggen (--gtest_break_on_failure) Hudson/Jenkins Integration via XML Ausgabe Testabdeckung mit GCC und LCOV einfach möglich 23
Toolintegration: LCOV 24
Schlussfolgerung Entwickeln und Testen in derselben Umgebung Jeder Testfall ist in sich abgeschlossen Schnelle Ausführung auf dem Host Einfaches Debugging Open-Source Gute Dokumentation Google Test und Google Mock sind hervorragende Frameworks um effizient C/C++ Code zu testen 25
Google Test code.google.com/p/googletest Google Mock code.google.com/p/googlemock Referenzen BSD Lizenz opensource.org/licenses/bsd-3-clause Effective C++ Testing Using Google Test docs.google.com/present/view?id=dfsbxvm5_0f5s4pvf9 Framework für Embedded SW www.embeddedcomputingconference.ch/pdf_2011/4c3-ziegler.pdf LCOV ltp.sourceforge.net/coverage/lcov.php 26