You are on page 1of 40

An Introduction to Google Test

Framework

Abner Huang
July. 2015
Test!? We do it every day
void Test__calc_isect() {
int x1, y1, x2, y2;
int x3, y3, x4, y4;
int x, y;

x1 = 0; y1 = INT_MIN; x2 = 2; y2 = INT_MAX;
x3 = 20; y3 = INT_MAX; x4 = 22; y4 = INT_MIN;

calc_isect(&x, &y, x1, y1, x2, y2, x3, y3, x4, y4, 0);

assert(x == 11);
assert(y == INT_MAX);
}
void main(void)
{
Test__calc_isect1();
Test__calc_isect2();
Test__calc_isect3();

Test__calc_isect();

Test__calc_isect4();
Test__calc_isect5();
Test__calc_isect6();
}
> ./test.out
test.cpp:100:Test__calc_isect(): Assertion `x == 11' failed.
void Test__calc_isect() {
int x1, y1, x2, y2;
int x3, y3, x4, y4;
int x, y;

x1 = 0; y1 = INT_MIN; x2 = 2; y2 = INT_MAX;
x3 = 20; y3 = INT_MAX; x4 = 22; y4 = INT_MIN;

calc_isect(&x, &y, x1, y1, x2, y2, x3, y3, x4, y4, 0);

if ((x != 11) || (y != INT_MAX))


{
printf(“Oops! (%d,%d) != (%d,%d)\n”,x,y,11,INT_MAX);
assert(0);
}
printf(“PASS\n”);
}
> ./test.out
PASS
PASS
PASS
Oops! (10,2147483647) != (11,2147483647)
test.cpp:100:Test__calc_isect(): Assertion `0' failed.
Any complains?
No convenient controls
Run in batch mode
Does gtest help?
No control of test suite
and test cases
./your_test.out --help
● Selecting Tests
● Repeating/Shuffling the Tests
● Generating an XML Report
● Turning Assertion Failures into Break-Points
○ --gtest_break_on_failure

● Disabling Catching Test-Thrown Exceptions


○ --gtest_catch_exceptions=0
> libpl_test --gtest_list_tests
CHK_ENCLOSE.
PlEnclose_SimpleInput
MAKE_BD.
MakeBd_LineTouchDirty
OSIZE_HDR.
OversizeHdr_BadOversizAmount
OversizeHdr_NULLInput
OversizeHdr_SimpleInput
OversizeHdr_OversizeOrthoHdr
OversizeHdr_OversizeNonOrthoHdr
OversizeOrthoHdr_OversizeOrthoHdr
BreakUpAngleHdr_DisconnectedInput
BreakUpAngleHdr_AngleBigInput
https://www.flickr.com/photos/marckjerland/4285433177 On Flickr, marc kjerland's Mathematician's toolkit
● Fatal and non-fatal assertions
○ EXPECT_EQ(x, 10);EXPECT_FLOAT_EQ(x,10.0)
○ ASSERT_EQ(x, 10);ASSERT_DOUBLE_EQ(x,10.0)

● Easy assertions informative messages:


assert(x == 10);

EXPECT_EQ(x, 10) << “vector (” << old_x <<


”,” << old_y << ”) moved to (” << x << ”,” <<
y << ”)\n”;
> ./test.out
[ RUN ] MYTEST.TestFoo
test.cpp:37: Failure
Value of: x
Actual: 11
Expected: 10
vector (10, 77) move to (11, 77)
[ FAILED ] MYTEST.TestFoo (0 ms)
DEATH TEST
calc_isect(int *x, int *y, int x1, int y1, int x2, int y2,
int x3, int y3, int x4, int y4, int tolerance)
{
if (x==NULL || y==NULL)
{
cerr << “Input is invalid.\n”;
exit(1);
}

… …
}
TEST(GEODeathTest, CalcIsect) {
ASSERT_DEATH(CalcIsect(NULL, NULL, 0,0,0,0,0,0,0,0,0),
".*invalid");
}
Adding Traces to Assertions
path/to/foo_test.cc:11: Failure
void Sub1(int n) {
Value of: Bar(n)
EXPECT_EQ(1, Bar(n));
Expected: 1
EXPECT_EQ(2, Bar(n + 1)); Actual: 2
} Trace:
path/to/foo_test.cc:17: A

TEST(FooTest, Bar) {
path/to/foo_test.cc:12: Failure
{ Value of: Bar(n + 1)
SCOPED_TRACE("A"); Expected: 2
Sub1(1);
}
Sub1(9);
}
XML outputs
<testsuites name="AllTests" tests="3" failures="
1" errors="0" time="35" ...>
<testsuite name="test_case_name" tests="2"
failures="1" errors="0" time="15"...>
<testcase name="test_name" status="run"
time="7"...>
<failure message="..."/>
<failure message="..."/>
</testcase>
</testsuite>
</testsuites>
Prepare your test case
• test.cpp contains main() in test directory
#include "_test_util.h"

static void
infrastructure_init(void)
{
vmemUseMalloc(1);
vmemInit_m();
vmemSetIncrementValue(VMEM_MEGABYTE_MINUS);
hoVMsetDefaultPoolLockingState(0);
vth_init();
}

int main(int argc, char **argv) {


infrastructure_init(); // Write a function like this to initialize vmem, threading etc.

::testing::InitGoogleTest(&argc, argv);
int result = RUN_ALL_TESTS(); Initialize gtest and runs all tests.
return result;
}
Test types of Gtest

• TEST() SetUp()

• TEST_F() -- Fixture

TearDown() TEST/TEST_F/TEST_P

• TEST_P() -- Value-parameterized fixture


– Range()
– Values()
– ValuesIn()
– Bool()
– Combine()
TEST(GEO, CalcIsect) {
int x1, y1, x2, y2;
int x3, y3, x4, y4;
int x, y;

x1 = 0; y1 = INT_MIN; x2 = 2; y2 = INT_MAX;
x3 = 20; y3 = INT_MAX; x4 = 22; y4 = INT_MIN;

calc_isect(&x, &y, x1, y1, x2, y2, x3, y3, x4, y4, 0);

assert(x == 11);
assert(y == INT_MAX);
}
Test Fixtures

• Sometimes you want to run several tests on similar data


structures (same setup before running test).
• In a fixture you define common setup/tear-down for
multiple tests
• Reduces amount of test code by avoiding repetition
class GEO : public ::testing::Test {
protected:
virtual void SetUp() {}
void ZapMemoryPool() {}
virtual void TearDown() {}
int x1, y1, x2, y2, x3, y3, x4, y4, x, y;
};

TEST_F(GEO, CalcIsect) {
x1 = 0; y1 = INT_MIN; x2 = 2; y2 = INT_MAX;
x3 = 20; y3 = INT_MAX; x4 = 22; y4 = INT_MIN;
calc_isect(&x, &y, x1, y1, x2, y2, x3, y3, x4, y4, 0);
assert(x == 11);
assert(y == INT_MAX);
}
TEST_P() -- Value-parameterized fixture

● generator based tests.

Range(begin, end[, Yields values {begin, begin+step, begin+step+step, ...}. The values do
step]) not include end. step defaults to 1.

Values(v1, v2, ..., vN) Yields values {v1, v2, ..., vN}.

ValuesIn(container) and Yields values from a C-style array, an STL-style container, or an


ValuesIn(begin, end) iterator range [begin, end). container, begin, and end can be
expressions whose values are determined at run time.
Bool() Yields sequence {false, true}.

Combine(g1, g2, ..., Yields all combinations (the Cartesian product for the math savvy) of
gN) the values generated by the N generators. This is only available if your
system provides the <tr1/tuple> header.
class GEO : public ::testing::TestWithParam<int> {
protected:
virtual void SetUp() {}
void ZapMemoryPool() {}
virtual void TearDown() {}
int x1, y1, x2, y2, x3, y3, x4, y4, x, y;
};

INSTANTIATE_TEST_CASE_P(AUTO_GEN_OH, GEO, ::testing::Range(1,12,1));

TEST_P(GEO, CalcIsect) {
double angle = PI/180 * 15 * GetParam();
x1 = -100; y1 = 0; x2 = 100; y2 = 0;
x3 = -50; y3 = 0; x4 = 50; y4 = 0;
rotate(&x3, &y4, angle);
rotate(&x4, &y4, angle);
calc_isect(&x, &y, x1, y1, x2, y2, x3, y3, x4, y4, 0);
assert(x == 0 && y == 0);
}
[----------] 16 tests from AUTO_GEN_OH/GEO
[ RUN ] AUTO_GEN_OH/GEO.CalcIsect/1
[ OK ] AUTO_GEN_OH/GEO.CalcIsect/1 (0 ms)
[ RUN ] AUTO_GEN_OH/GEO.CalcIsect/2
[ OK ] AUTO_GEN_OH/GEO.CalcIsect/2 (0 ms)
[ RUN ] AUTO_GEN_OH/GEO.CalcIsect/3
[ OK ] AUTO_GEN_OH/GEO.CalcIsect/3 (0 ms)
[ RUN ] AUTO_GEN_OH/GEO.CalcIsect/4
[ OK ] AUTO_GEN_OH/GEO.CalcIsect/4 (0 ms)
[ RUN ] AUTO_GEN_OH/GEO.CalcIsect/5
[ OK ] AUTO_GEN_OH/GEO.CalcIsect/5 (0 ms)
[ RUN ] AUTO_GEN_OH/GEO.CalcIsect/6
[ OK ] AUTO_GEN_OH/GEO.CalcIsect/6 (0 ms)
[ RUN ] AUTO_GEN_OH/GEO.CalcIsect/7
[ OK ] AUTO_GEN_OH/GEO.CalcIsect/7 (0 ms)
[ RUN ] AUTO_GEN_OH/GEO.CalcIsect/8
[ OK ] AUTO_GEN_OH/GEO.CalcIsect/8 (0 ms)
[ RUN ] AUTO_GEN_OH/GEO.CalcIsect/9
[ OK ] AUTO_GEN_OH/GEO.CalcIsect/9 (0 ms)
[ RUN ] AUTO_GEN_OH/GEO.CalcIsect/10
[ OK ] AUTO_GEN_OH/GEO.CalcIsect/10 (0 ms)
[ RUN ] AUTO_GEN_OH/GEO.CalcIsect/11
[ OK ] AUTO_GEN_OH/GEO.CalcIsect/11 (0 ms)
[----------] 11 tests from AUTO_GEN_OH/GEO (0 ms total)
Organization of Tests

TEST(GEO, CalcIsect) Test Suite


test case test
Flow of Running Tests

Environment::
SetUpTestCase()
SetUp()

SetUp()

TearDown() TEST/TEST_F/TEST_P

Environment::
TearDownTestCase()
TearDown()
How to install gtest
Easy Install
> wget http://googletest.googlecode.com/files/gtest-1.7.0.zip
> unzip gtest-1.7.0.zip
> cd gtest-1.7.0
> ./configure
> make
> cp -a include/gtest /usr/include
> sudo cp -a lib/.libs/* /usr/lib/
How to use google test

• You must check out gtest to use unit test feature. We do


not have the executable of gtest.
• E.g.
– /path/to/foo/
– build
– arch
– src
– exec
– gtest
– include
– lib
How to use google test (II)

• E.g.
/path/to/foo/
– exec
– gtest
– include
– lib
– bar <<< Library under test, contains production code
– published
– test <<< Directory contains test code

test> make
Some points to keep in mind

• gtest is useful for testing primitive functions in libraries


• Unit testing does not replace regression testing
• With gtest:
– You do not modify production code.
– You add test code that calls library functions.
– You check-in test code to repository
• Production code is not compiled/linked with gtest
• Using gtest creates a test binary, not icv binary
Coding Style and Rules

• Don’t mix TEST(), TEST_F(), TEST_P()


• Don’t use global variables, use test fixture to instead
• Gtest does not reuse the same test fixture object across
multiple tests
• Spell SetUp() correctly.
• Gtest use fork() to do death test, do not try not to free
memory in a death test.
• You can derive new class from your own class.
Coding Style and Rules

• Use Camel Case style to name test cases and suite


– E.g., TEST(Time, Flies_Like_An_Arrow) { ... }
and
TEST(Time_Flies, Like_An_Arrow) { … }
will have the same name
Time_Files_Like_An_Arrow_Test

• Current Naming Rule


– Test suite name is all uppercase
– Test case name is Camel Case style with underscore.
– E.g., TEST_F(SPACING_UTIL__PNT_EDGE, WhichHalfRes_SamePoints)
Key Features & Characters Boost Test Google Test UnitTest++

Free (Open Source) software Yes Yes Yes

Simple to use Yes Yes Yes


(5 out of 5) (5 out of 5) (4 out of 5)

Test cases grouping & organization Good Good Normal

Test case template support Yes Yes Yes

Test fixture (i.e. fixed state used as Yes Yes Yes


a baseline for running test) support

Global test fixture Yes Yes No

Handle C++ exceptions Yes Yes Yes

Different types of assertions support Yes Yes No

Fatal and non-fatal assertions Yes Yes No

Support Regular Expression when Yes Yes No


matching function output

Output in XML format Yes Yes No


Key Features & Characters Boost Test Google Test UnitTest++

Support Mock object (objects can No Yes No


simulate the behavior of complex (work seamlessly with
objects) Google Mock)

Extend features with event No Yes No


mechanism

Run tests on distributed machines No Yes No

Thread safety when running tests No Yes No

Run subset of all defined test cases Yes Yes No


(only support (support multiple
filtering by test filtering conditions)
name)

• Karl Chen, C++ Unit Testing Frameworks Evaluation


Thank you

You might also like