Hi,
I'm glad to report that support for
typed tests and
type-parameterized tests has been committed to the svn. If you check out the head revision, you can try it for yourself. Many people contributed ideas, reviews, and feedback on earlier iterations of the implementation. You know who they are if you have been following our discussions on this earlier. :-)
In case you don't know what type-parameterized tests are, they are
abstract test patterns parameterized by a type. They allow you to define a test suite once and instantiate it with different type arguments later. I have update
http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide with the usage. Here's a copy:
Suppose
you have multiple implementations of the same interface and want to
make sure that all of them satisfy some common requirements. Or, you
may have defined several types that are supposed to conform to the same
"concept" and you want to verify it. In both cases, you want the same
test logic repeated for different types.
While you can write one TEST or TEST_F for each type you want to test (and you may even factor the test logic into a function template that you invoke from the TEST), it's tedious and doesn't scale: if you want m tests over n types, you'll end up writing m*n TESTs.
Typed tests
allow you to repeat the same test logic over a list of types. You only
need to write the test logic once, although you must know the type list
when writing typed tests. Here's how you do it:
First, define a fixture class template. It should be parameterized by a type. Remember to derive it from testing::Test:
template <typename T>
class FooTest : public testing::Test {
public:
...
typedef std::list<T> List;
static T shared_;
T value_;
};
Next, associate a list of types with the test case, which will be repeated for each type in the list:
typedef testing::Types<char, int, unsigned int> MyTypes;
TYPED_TEST_CASE(FooTest, MyTypes);
The typedef is necessary for the TYPED_TEST_CASE macro to parse correctly. Otherwise the compiler will think that each comma in the type list introduces a new macro argument.
Then, use TYPED_TEST() instead of TEST_F() to define a typed test for this test case. You can repeat this as many times as you want:
TYPED_TEST(FooTest, DoesBlah) {
// Inside a test, refer to the special name TypeParam to get the type
// parameter. Since we are inside a derived class template, C++ requires
// us to visit the members of FooTest via 'this'.
TypeParam n = this->value_;
// To visit static members of the fixture, add the 'TestFixture::'
// prefix.
n += TestFixture::shared_;
// To refer to typedefs in the fixture, add the 'typename TestFixture::'
// prefix. The 'typename' is required to satisfy the compiler.
typename TestFixture::List values;
values.push_back(n);
...
}
TYPED_TEST(FooTest, HasPropertyA) { ... }
You can see samples/sample6_unittest.cc for a complete example.
Availability: Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.1.0.
Type-parameterized tests
are like typed tests, except that they don't require you to know the
list of types ahead of time. Instead, you can define the test logic
first and instantiate it with different type lists later. You can even
instantiate it more than once in the same program.
If
you are designing an interface or concept, you can define a suite of
type-parameterized tests to verify properties that any valid
implementation of the interface/concept should have. Then, the author
of each implementation can just instantiate the test suite with his
type to verify that it conforms to the requirements, without having to
write similar tests repeatedly. Here's an example:
First, define a fixture class template, as we did with typed tests:
template <typename T>
class FooTest : public testing::Test {
...
};
Next, declare that you will define a type-parameterized test case:
TYPED_TEST_CASE_P(FooTest);
The _P suffix is for "parameterized" or "pattern", whichever you prefer to think.
Then, use TYPED_TEST_P() to define a type-parameterized test. You can repeat this as many times as you want:
TYPED_TEST_P(FooTest, DoesBlah) {
// Inside a test, refer to TypeParam to get the type parameter.
TypeParam n = 0;
...
}
TYPED_TEST_P(FooTest, HasPropertyA) { ... }
Now the tricky part: you need to register all test patterns using the REGISTER_TYPED_TEST_CASE_P
macro before you can instantiate them. The first argument of the macro
is the test case name; the rest are the names of the tests in this test
case:
REGISTER_TYPED_TEST_CASE_P(FooTest,
DoesBlah, HasPropertyA);
Finally, you are free to instantiate the pattern with the types you want. If you put the above code in a header file, you can #include it in multiple C++ source files and instantiate it multiple times.
typedef testing::Types<char, int, unsigned int> MyTypes;
INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
To distinguish different instances of the pattern, the first argument to the INSTANTIATE_TYPED_TEST_CASE_P macro is a prefix that will be added to the actual test case name. Remember to pick unique prefixes for different instances.
In the special case where the type list contains only one type, you can write that type directly without testing::Types<...>, like this:
INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
You can see samples/sample6_unittest.cc for a complete example.
Availability: Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.1.0.
Please let me know if you have any questions. Cheers,
--
Zhanyong