Skip to content

Commit

Permalink
Update 2023-7-16-gtest.md
Browse files Browse the repository at this point in the history
Describe GTest testing
  • Loading branch information
sdomoszlai13 authored May 24, 2024
1 parent 9df7509 commit 7be9126
Showing 1 changed file with 130 additions and 2 deletions.
132 changes: 130 additions & 2 deletions _posts/2023-7-16-gtest.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ In the age of StackOverflow, ChatGPT etc. the casual software developer can be o

Let's suppose you found a perfect AI tool that spits out working code for every task you ask it to solve (yes, that's not really possible, but let's suppose it is).

> ## *Now, would you ask your AI companion to write an autopilot software for a passanger plane, then upload it to the flight computer and board the plane to fly? If you would, don't continue reading, but *please* don't become an aerospace engineer.*
> ## *Now, would you ask your AI companion to write an autopilot software for a passanger plane, then upload it to the flight computer and board the plane to fly? If you would, don't continue reading and *please* don't become an aerospace engineer.*
Software testing has always been an important task in the software development lifecycle. As more and more code is AI generated, testing will probably become even more important. For this task, a number of tools have been designed in the last decades, e.g. for

Expand Down Expand Up @@ -32,7 +32,135 @@ A few guidelines for good test cases are gathered below.
* preferably, tests should be fast
* failed tests should provide as much information as possible about the failure

Google Test provides to distinct basic ways for tests to indicate something's wrong:
Google Test provides two distinct basic ways for tests to indicate something's wrong:

* assertion: test execution stops if the outcome isn't as expected (for fatal failures)
* expectation: test execution continues if the outcome isn't as expected (for non-fatal failures)

Let's look at some examples. Let's suppose we've written a (arguably really silly) function that calculates exponents of e:


File: `exponential.h`
```c++
#ifndef EXPONENTIAL_H
#define EXPONENTIAL_H

double exponential(double x);

#endif // EXPONENTIAL_H

```


File: `exponential.cpp`
```c++
#include "exponential.h"
#include <cmath>

double exponential(double x) {
return std::exp(x);
}

```
For this simple program, we can write the following tests:
File: `exponential_test.cpp`
```c++
#include <gtest/gtest.h>
#include "exponential.h"
// Fixture class for Exponential function
class ExponentialTest : public ::testing::Test {
protected:
void SetUp() override {
// Code here will be called immediately after the constructor (right before each test)
}
void TearDown() override {
// Code here will be called immediately after each test (right before the destructor)
}
};
// Test functions
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
```

Now, we can replace the placeholder comment with actual test functions. Let's start by checking if positive exponents are handled correctly:

```c++
TEST_F(ExponentialTest, HandlesPositiveInput) {
EXPECT_DOUBLE_EQ(exponential(1.0), std::exp(1.0));
EXPECT_DOUBLE_EQ(exponential(2.0), std::exp(2.0));
EXPECT_DOUBLE_EQ(exponential(10.0), std::exp(10.0));
}
```
Then we check the 0 case:
```c++
TEST_F(ExponentialTest, HandlesZeroInput) {
EXPECT_DOUBLE_EQ(exponential(0.0), 1.0);
}
```

Next, we check negative exponents:

```c++
TEST_F(ExponentialTest, HandlesNegativeInput) {
EXPECT_DOUBLE_EQ(exponential(-1.0), std::exp(-1.0));
EXPECT_DOUBLE_EQ(exponential(-2.0), std::exp(-2.0));
EXPECT_DOUBLE_EQ(exponential(-10.0), std::exp(-10.0));
}
```
Lastly, we check fractional exponents:
```c++
TEST_F(ExponentialTest, HandlesFractionalInput) {
EXPECT_DOUBLE_EQ(exponential(0.5), std::exp(0.5));
EXPECT_DOUBLE_EQ(exponential(-0.5), std::exp(-0.5));
EXPECT_DOUBLE_EQ(exponential(1.5), std::exp(1.5));
}
```

We can now compile and run the above function and test files with

```bash
g++ -std=c++11 -isystem /usr/local/include -pthread exponential.cpp test_exponential.cpp /usr/local/lib/libgtest.a /usr/local/lib/libgtest_main.a -o test
./test
```
if using the standard installation paths.
If all goes well, we now see the output

```scss
[==========] Running 4 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 4 tests from ExponentialTest
[ RUN ] ExponentialTest.HandlesZeroInput
[ OK ] ExponentialTest.HandlesZeroInput (0 ms)
[ RUN ] ExponentialTest.HandlesPositiveInput
[ OK ] ExponentialTest.HandlesPositiveInput (0 ms)
[ RUN ] ExponentialTest.HandlesNegativeInput
[ OK ] ExponentialTest.HandlesNegativeInput (0 ms)
[ RUN ] ExponentialTest.HandlesFractionalInput
[ OK ] ExponentialTest.HandlesFractionalInput (0 ms)
[----------] 4 tests from ExponentialTest (0 ms total)

[----------] Global test environment tear-down
[==========] 4 tests from 1 test suite ran. (0 ms total)
[ PASSED ] 4 tests.
```

which indicates that all our test ran and passed. Great, our oneliner function is now tested by multiple functions!


## pytest

The process is fairly similar in Python.

0 comments on commit 7be9126

Please sign in to comment.