Value-parameterized tests allow you to test your code with different parameters without writing multiple copies of the same test.
Suppose you write a testfor your code and then realize that your code is affected by a presence of a Boolean command line flag.
TEST(MyCodeTest, TestFoo) {
// A code to test foo().
}
Usually people factor their test code into a function with a Boolean parameter in such situations. The function sets the flag, then executes the testing code.
void TestFooHelper(bool flag_value) {
flag = flag_value;
// A code to test foo().
}
TEST(MyCodeTest, TestFoo) {
TestFooHelper(false);
TestFooHelper(true);
}
缺点:
But this setup has serious drawbacks. First, when a test assertion fails in your tests, it becomes unclear what value of the parameter caused it to fail. You can stream a clarifying message into your EXPECT/ASSERT statements, but it you'll have to do it with all of them. Second, you have to add one such helper function per test. What if you have ten tests? Twenty? A hundred?
Value-parameterized tests will let you write your test only once and then easily instantiate and run it with an arbitrary number of parameter values.
Here are some other situations when value-parameterized tests come handy:
You want to test different implementations of an OO interface.
You want to test your code over various inputs (a.k.a. data-driven testing). This feature is easy to abuse, so please exercise your good sense when doing it!
高档做法
How to Write Value-Parameterized Tests
To write value-parameterized tests, first you should define a fixture class. It must be derived from both ::testing::Test and ::testing::WithParamInterface (the latter is a pure interface), where T is the type of your parameter values. For convenience, you can just derive the fixture class from ::testing::TestWithParam, which itself is derived from both ::testing::Test and ::testing::WithParamInterface. T can be any copyable type. If it's a raw pointer, you are responsible for managing the lifespan of the pointed values.
第一步 继承 ::testing::TestWithParam
用法1
class FooTest :public::testing::TestWithParam<const char*> {
// You can implement all the usual fixture class members here.
// To access the test parameter,call GetParam() from class
// TestWithParam<T>.
};
用法2
// Or, when you want to add parameters to a pre-existing fixture class:
Then, use the TEST_P macro to define as many test patterns using this fixture as you want. The _P suffix is for"parameterized"or"pattern", whichever you prefer to think.
第二步使用
TEST_P(FooTest, DoesBlah) {
// Inside a test, access the test parameter with the GetParam() method
// of the TestWithParam<T> class:
EXPECT_TRUE(foo.Blah(GetParam()));
...
}
TEST_P(FooTest, HasBlahBlah) {
...
}
Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test case with any set of parameters you want. Google Test defines a number of functions for generating test parameters. They return what we call( parameter generators. Here is a summary of them, which are all in the testing namespace:
Range(begin, end[, step]) Yields values {begin, begin+step, begin+step+step,...}. The values do notinclude end. step defaults to 1.
ValuesIn(container)and ValuesIn(begin, end) Yields values from a C-style array, an STL-style container,or an 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,..., gN) Yields all combinations (the Cartesian product for the math savvy)of the values generated by the N generators.This is only available if your system provides the <tr1/tuple> header.If you are sure your system does,and Google Test disagrees, you can override it by defining GTEST_HAS_TR1_TUPLE=1. See comments ininclude/gtest/internal/gtest-port.h for more information.
For more details, see the comments at the definitions of these functions in the source code.
The following statement will instantiate tests from the FooTest test case each with parameter values "meeny","miny",and"moe".
第三步 初始化的值
INSTANTIATE_TEST_CASE_P(InstantiationName,
FooTest,
::testing::Values("meeny","miny","moe"));
To distinguish different instances of the pattern (yes, you can instantiate it more than once), the first argument to INSTANTIATE_TEST_CASE_P is a prefix that will be added to the actual test case name. Remember to pick unique prefixes for different instantiations. The tests from the instantiation above will have these names:
Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests in the given test case, whether their definitions come before or after the INSTANTIATE_TEST_CASE_P statement.
You can see these files for more examples.
Availability: Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.2.0.
总结
Creating Value-Parameterized Abstract Tests
In the above, we define and instantiate FooTest in the same source file. Sometimes you may want to define value-parameterized tests in a library and let other people instantiate them later.This pattern is known as abstract tests. As an example of its application, when you are designing an interface you can write a standard suite of abstract tests (perhaps using a factory function as the test parameter) that all implementations of the interface are expected to pass. When someone implements the interface, he can instantiate your suite to get all the interface-conformance tests for free.
To define abstract tests, you should organize your code like this:
Put the definition of the parameterized test fixture class (e.g. FooTest)in a header file, say foo_param_test.h. Think ofthis as declaring your abstract tests.
Put the TEST_P definitions in foo_param_test.cc, which includes foo_param_test.h. Think ofthis as implementing your abstract tests.
Once they are defined, you can instantiate them by including foo_param_test.h, invoking INSTANTIATE_TEST_CASE_P(),and linking with foo_param_test.cc. You can instantiate the same abstract test case multiple times, possibly in different source files.