## GTEST * TEST(...) Create single test * TEST_F(...) Use fixtures for testing * TEST_P(...) Use package of parameters for all tests * EXPECT_* Check condition * ASSERT_* Check condition and stop test if fails. * EXPECT_PRED* Allow to create own predicate, and other format of display errors * testing::FloatLE and testing::DoubleLE can be use for EXPECT_PRED_FORMAT* for floating-point comparison * GTEST_SKIP() can be use for skipping the test * EXPECT_EXIT can test signall which end program, like: SIGKILL * EXPECT_THROW will catch and check exceptions ___ ## TEST To create a simple test we can use `TEST` macro ```C++ class Calculator { public: int add(int lsh, int rhs) { return lhs + rhs; } }; TEST(CalculatorTest, ShouldAddTwoValues) { Calculator calc; EXPECT_EQ(calc.add(10, 20), 10 + 20); } ``` ___ ## TEST_F If we need to set up some structures before creating a test, we shouldn't do this every test, but instead create a test fixture that sets everything up during construction. It also provides useful methods which we can use in every test. This fixture is created first, then a test starts. ```C++ class DownloaderTest : public testing::Test { public: DownloaderTest() { _connection = std::make_unique(); _connection->set_certificates(_certificateMock); _downloader = std::make_unqiue(_connection.get()); } CertificateMock _certificateMock; std::unqiue_ptr _connection; std::unique_ptr _downloader; }; TEST_F(DownloaderTest, shouldDownloadImage) { EXPECT_CALL(_certificateMock, validate).WillOnce(Return(true)); EXPECT_TRUE(_downloader.downloadImage("exampleImg")); } ``` ___ ## TEST_P (1) Whenever we need to run the same test but with a different set of parameters we should use `TEST_P` ```C++ class Firewall { public: virtual ~Firewall() = default; virtual bool block(const std::string& ipAddress) = 0; }; class WhiteListFirewall : public Firewall { public: void addToWhitelist(const std::string& ipAddress) { whiteList_.push_back(ipAddress); } bool block(const std::string& ipAddress) override { return std::find(cbegin(whiteList_), cend(whiteList_), ipAddress) == std::cend(whiteList_); } private: std::vector whiteList_; }; ``` ___ ## TEST_P (2) ```C++ class TestFirewall : public testing::TestWithParam> { }; TEST_P(TestFirewall, ShouldFilterAdresses) { auto firewall = std::make_unique(); firewall->addToWhitelist("192.201.1.12"); firewall->addToWhitelist("192.122.1.12"); const auto& [address, isBlock] = GetParam(); EXPECT_EQ(firewall->block(address), isBlock); } INSTANTIATE_TEST_SUITE_P(TestFirewallParameters, TestFirewall, testing::Values( std::pair{"192.178.1.12", true}, std::pair{"192.144.1.12", true}, std::pair{"192.188.1.12", true}, std::pair{"192.201.1.12", false}, std::pair{"192.122.1.12", false})); ``` ___ ## TEST_P (3) ``` [----------] 5 tests from TestFirewallParameters/TestFirewall [ RUN ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/0 [ OK ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/0 (0 ms) [ RUN ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/1 [ OK ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/1 (0 ms) [ RUN ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/2 [ OK ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/2 (0 ms) [ RUN ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/3 [ OK ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/3 (0 ms) [ RUN ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/4 [ OK ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/4 (0 ms) [----------] 5 tests from TestFirewallParameters/TestFirewall (0 ms total) ``` ___ ## TEST_P - inherit from other test ```C++ class BlackListFirewall : public Firewall { public: void addToBlacklist(const std::string& ipAddress) { blackList_.push_back(ipAddress); } bool block(const std::string& ipAddress) override { return std::find(cbegin(blackList_), cend(blackList_), ipAddress) != std::cend(blackList_); } private: std::vector blackList_; }; class BaseTestBlackListFirewall : public testing::Test { public: void SetUp() override { firewall_ = std::make_unique(); firewall_->addToBlacklist("192.201.1.12"); firewall_->addToBlacklist("192.122.1.12"); firewall_->addToBlacklist("192.178.1.12"); firewall_->addToBlacklist("192.144.1.12"); firewall_->addToBlacklist("192.188.1.12"); } BlackListFirewall* firewall() const { return firewall_.get(); } private: std::unique_ptr firewall_; }; ``` ___ ## testing::WithParamInterface ```C++ class TestBlackListFirewall : public BaseTestBlackListFirewall, public testing::WithParamInterface { }; TEST_P(TestBlackListFirewall, ShouldBlock) { EXPECT_TRUE(firewall()->block(GetParam())); } INSTANTIATE_TEST_SUITE_P(TestBlackListFirewallPackage, TestBlackListFirewall, testing::Values( "192.178.1.12", "192.144.1.12", "192.188.1.12", "192.201.1.12", "192.122.1.12")); ``` ``` [----------] 5 tests from TestBlackListFirewallPackage/TestBlackListFirewall [ RUN ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/0 [ OK ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/0 (0 ms) [ RUN ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/1 [ OK ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/1 (0 ms) [ RUN ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/2 [ OK ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/2 (0 ms) [ RUN ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/3 [ OK ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/3 (0 ms) [ RUN ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/4 [ OK ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/4 (0 ms) [----------] 5 tests from TestBlackListFirewallPackage/TestBlackListFirewall (0 ms total) ``` ___ ## EXPECT_PRED* - own error message ```C++ testing::AssertionResult isBlocked(Firewall* firewall, const std::string& addr, bool block) { if (firewall->block(addr) == block) { return testing::AssertionSuccess(); } return testing::AssertionFailure() << addr << (block ? " should be blocked" : " shouldn't be blocked"); } TEST_F(BaseTestBlackListFirewall, ShouldFilter) { EXPECT_TRUE(isBlocked(firewall(), "192.188.1.12", true)); EXPECT_TRUE(isBlocked(firewall(), "192.188.1.12", false)); } ``` ``` [----------] 1 test from BaseTestBlackListFirewall [ RUN ] BaseTestBlackListFirewall.ShouldFilter /home/mateusz.adamski/Documents/repoGit/advanced_cpp/examples/gtest.cpp:101: Failure Value of: isBlocked(firewall(), "192.188.1.12", false) Actual: false (192.188.1.12 shouldn't be blocked) Expected: true [ FAILED ] BaseTestBlackListFirewall.ShouldFilter (0 ms) [----------] 1 test from BaseTestBlackListFirewall (0 ms total) ``` ___ ## EXPECT_PRED* - check string ```C++ for (const auto& str : {"There is a nauka!", "nauka.programowania.ma@gmail.com"}) { EXPECT_THAT(str, testing::MatchesRegex( "^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$")); ASSERT_THAT(str, testing::HasSubstr("nauka")); } ``` ``` [ RUN ] ExampleTest.ShouldFail /home/mateusz.adamski/Documents/repoGit/advanced_cpp/examples/gtest.cpp:104: Failure Value of: str Expected: matches regular expression "^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$" Actual: 0x5625cd2c080c pointing to "There is a nauka!" (of type char const*) [ FAILED ] ExampleTest.ShouldFail (0 ms) [----------] 1 test from ExampleTest (0 ms total) ``` ___ ## EXPECT_PRED* - comparison of floating point numbers ```C++ std::vector> vec{ {43.45, 43.45}, {44.34321, 45.1234}, {1.12, 1.1199999}}; for (const auto& [lhs, rhs] : vec) { EXPECT_PRED_FORMAT2(testing::FloatLE, lhs, rhs); EXPECT_PRED_FORMAT2(testing::DoubleLE, lhs, rhs); } ``` ``` [ RUN ] ExampleTest.ShouldFail /home/mateusz.adamski/Documents/repoGit/advanced_cpp/examples/gtest.cpp:108: Failure Expected: (lhs) <= (rhs) Actual: 1.1200000000000001 vs 1.1199999 [ FAILED ] ExampleTest.ShouldFail (0 ms) [----------] 1 test from ExampleTest (0 ms total) [----------] Global test environment tear-down ``` ___ ## GTEST_SKIP ```C++ TEST(ExampleTest, ShouldFail) { GTEST_SKIP() << "Skipping test PR12345"; std::vector> vec{ {43.45, 43.45}, {44.34321, 45.1234}, {1.12, 1.1199999}}; for (const auto& [lhs, rhs] : vec) { EXPECT_PRED_FORMAT2(testing::FloatLE, lhs, rhs); EXPECT_PRED_FORMAT2(testing::DoubleLE, lhs, rhs); } } ``` ``` [ RUN ] ExampleTest.ShouldFail /home/mateusz.adamski/Documents/repoGit/advanced_cpp/examples/gtest.cpp:102: Skipped Skipping test PR12345 ``` ___ ## Skipp all fixture ```C++ class BaseTestBlackListFirewall : public testing::Test { public: void SetUp() override { GTEST_SKIP() << "Skipping test PR12345"; firewall_ = std::make_unique(); firewall_->addToBlacklist("192.201.1.12"); firewall_->addToBlacklist("192.122.1.12"); firewall_->addToBlacklist("192.178.1.12"); firewall_->addToBlacklist("192.144.1.12"); firewall_->addToBlacklist("192.188.1.12"); } BlackListFirewall* firewall() const { return firewall_.get(); } private: std::unique_ptr firewall_; }; ``` ``` [----------] 3 tests from BaseTestBlackListFirewall [ RUN ] BaseTestBlackListFirewall.ShouldFilter /home/mateusz.adamski/Documents/repoGit/advanced_cpp/examples/gtest.cpp:76: Skipped Skipping test PR12345 [ SKIPPED ] BaseTestBlackListFirewall.ShouldFilter (0 ms) [ RUN ] BaseTestBlackListFirewall.ShouldNotFilter /home/mateusz.adamski/Documents/repoGit/advanced_cpp/examples/gtest.cpp:86: Skipped Skipping test PR12345 [ SKIPPED ] BaseTestBlackListFirewall.ShouldNotFilter (0 ms) [ RUN ] BaseTestBlackListFirewall.ShouldReportError /home/mateusz.adamski/Documents/repoGit/advanced_cpp/examples/gtest.cpp:96: Skipped Skipping test PR12345 [ SKIPPED ] BaseTestBlackListFirewall.ShouldReportError (0 ms) [----------] 3 tests from BaseTestBlackListFirewall (0 ms total) ``` ___ ## EXPECT_EXIT and EXPECT_THROW ```C++ TEST(MyDeathTest, NormalExit) { EXPECT_EXIT(normalExit(), testing::ExitedWithCode(0), "Succes"); } TEST(MyDeathTest, KillProcess) { EXPECT_EXIT(killProcess(), testing::KilledBySignal(SIGKILL), "Sending myself unblockable signal"); } void foo(int val) { if (val != 42) { throw std::runtime_error("Wrong number"); } } TEST(MyDeathTest, NormalExit) { EXPECT_THROW(foo(5), std::runtime_error); } ``` ___ ## Sharing Resources Between Tests ```C++ struct Foo { std::string name_; int value_; }; class FooTest : public testing::Test { public: // Shared static void SetUpTestSuite() { if (!shared_resource_) { shared_resource_ = std::make_unique(); shared_resource_->name_ = "Shared Foo!\n"; shared_resource_->value_ = 42; } } // Shared static void TearDownTestSuite() { shared_resource_ = nullptr; } // Per-test void SetUp() override {} // Per-test void TearDown() override {} protected: inline static std::unique_ptr shared_resource_; }; TEST_F(FooTest, Test1) { EXPECT_EQ(FooTest::shared_resource_->name_, "Shared Foo!\n"); EXPECT_EQ(FooTest::shared_resource_->value_, 42); FooTest::shared_resource_->name_ = "Foo!!!"; FooTest::shared_resource_->value_ = 13; } TEST_F(FooTest, Test2) { EXPECT_EQ(FooTest::shared_resource_->name_, "Foo!!!"); EXPECT_EQ(FooTest::shared_resource_->value_, 13); } ``` ___ ## Testing private code - should be avoided ```C++ class Foo { private: FRIEND_TEST(FooTest, PrivateTest); int doSth(int val) { return val; } }; TEST(FooTest, PrivateTest) { Foo foo; EXPECT_EQ(foo.doSth(42), 42); } ``` ___ ## Exercise 1 Open project **SHM** and write test for class `Ship.cpp` which will test it's interface. Remember to test edge cases :). Test it well and fix issues. Go to `Presentation/exercises/SHM/build/test` and run test using command `./SHM_Tests`.