## 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`.