diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/unittest/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/unittest/fixture_test.cpp | 88 | ||||
-rw-r--r-- | src/mongo/unittest/unittest.cpp | 18 | ||||
-rw-r--r-- | src/mongo/unittest/unittest.h | 39 |
4 files changed, 140 insertions, 7 deletions
diff --git a/src/mongo/unittest/SConscript b/src/mongo/unittest/SConscript index 43eaf408862..12195e92fb4 100644 --- a/src/mongo/unittest/SConscript +++ b/src/mongo/unittest/SConscript @@ -12,4 +12,4 @@ env.StaticLibrary("unittest_crutch", ['crutch.cpp']) env.CppUnitTest('unittest_test', 'unittest_test.cpp') - +env.CppUnitTest('fixture_test', 'fixture_test.cpp') diff --git a/src/mongo/unittest/fixture_test.cpp b/src/mongo/unittest/fixture_test.cpp new file mode 100644 index 00000000000..3a31dab3219 --- /dev/null +++ b/src/mongo/unittest/fixture_test.cpp @@ -0,0 +1,88 @@ +/** + * Copyright (C) 2012 10gen Inc. + */ + +/** + * Unit tests of the unittest framework itself. + */ + +#include "mongo/unittest/unittest.h" + +namespace { + + class TestFixture : public mongo::unittest::Test { + protected: + int _myVar; + static int _num_set_ups; + static int _num_tear_downs; + + void setUp() { + _num_set_ups++; + _myVar = 10; + } + + void tearDown() { + _num_tear_downs++; + _myVar = 0; + } + + int inc() { + return ++_myVar; + } + + void throwSpecialException() { + throw FixtureExceptionForTesting(); + } + + }; + + int TestFixture::_num_set_ups = 0; + int TestFixture::_num_tear_downs = 0; + + // NOTE: + // Test cases should not be designed that depend on the order they appear. But because + // we're testing the test framework itself, we do not follow this rule here and require the + // following four tests to be in that order. + + // vvvvvvvvvvvvvvvvvvvvvvvv Do not add tests below + + // This needs to be the very first test. Please, see NOTE above. + TEST_F(TestFixture, SetUpTest) { + ASSERT_EQUALS(_num_set_ups, 1); + ASSERT_EQUALS(_num_tear_downs, 0); + } + + // This needs to be the second test. Please, see NOTE above. + TEST_F(TestFixture, TearDownTest) { + ASSERT_EQUALS(_num_set_ups, 2); + ASSERT_EQUALS(_num_tear_downs, 1); + } + + // This needs to be the third/fourth test. Please, see NOTE above. We are + // finishing a test case by throwing an exception. Normally, the framework + // would treat this as an error. But what we'd like here is to make sure + // that the fixture tear down routines were called in that case. + TEST_F(TestFixture, Throwing) { + throwSpecialException(); + } + TEST_F(TestFixture, TearDownAfterThrowing ) { + // Make sure tear down was called in the test above this. + ASSERT_EQUALS(_num_tear_downs, 3); + } + + // ^^^^^^^^^^^^^^^^^^^^^^^^ Do not add test above + + // New tests may be added below. + + TEST_F(TestFixture, VariableAndMethodAccessTest) { + ASSERT_EQUALS(10, _myVar); + ASSERT_EQUALS(11, inc()); + } + + class EmptyFixture : public mongo::unittest::Test { + }; + + TEST_F(EmptyFixture, EmptyTest) { + } + +} // unnamed namespace diff --git a/src/mongo/unittest/unittest.cpp b/src/mongo/unittest/unittest.cpp index d67ad6ff6f3..44aaaabd5e6 100644 --- a/src/mongo/unittest/unittest.cpp +++ b/src/mongo/unittest/unittest.cpp @@ -78,7 +78,23 @@ namespace mongo { void Test::run() { setUp(); - _doTest(); + + // An uncaught exception does not prevent the tear down from running. But + // such an event still constitutes an error. To test this behavior we use a + // special exception here that when thrown does trigger the tear down but is + // not considered an error. + try { + _doTest(); + } + catch (FixtureExceptionForTesting&) { + tearDown(); + return; + } + catch (TestAssertionFailureException&) { + tearDown(); + throw; + } + tearDown(); } diff --git a/src/mongo/unittest/unittest.h b/src/mongo/unittest/unittest.h index 67277c4cd87..f1556cf291b 100644 --- a/src/mongo/unittest/unittest.h +++ b/src/mongo/unittest/unittest.h @@ -110,6 +110,33 @@ void _TEST_TYPE_NAME(CASE_NAME, TEST_NAME)::_doTest() /** + * Construct a single test named TEST_NAME that has access to a common class (a "fixture") + * named "FIXTURE_NAME". + * + * Usage: + * + * class FixtureClass : public mongo::unittest::Test { + * protected: + * int myVar; + * void setUp() { myVar = 10; } + * }; + * + * TEST(FixtureClass, TestThatUsesFixture) { + * ASSERT_EQUALS(10, myVar); + * } + */ +#define TEST_F(FIXTURE_NAME, TEST_NAME) \ + class _TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME) : public FIXTURE_NAME { \ + private: \ + virtual void _doTest(); \ + \ + static const RegistrationAgent<_TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME) > _agent; \ + }; \ + const ::mongo::unittest::Test::RegistrationAgent<_TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME) > \ + _TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)::_agent(#FIXTURE_NAME, #TEST_NAME); \ + void _TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)::_doTest() + +/** * Macro to construct a type name for a test, from its "CASE_NAME" and "TEST_NAME". * Do not use directly in test code. */ @@ -148,11 +175,6 @@ namespace mongo { /** * Base type for unit test fixtures. Also, the default fixture type used * by the TEST() macro. - * - * TODO(schwerin): Implement a TEST_F macro that allows testers to specify - * different subclasses of Test to be used as the test fixture. These subclasses - * could then provide per-test set-up and tear-down code by overriding the - * setUp and tearDown methods. */ class Test : private boost::noncopyable { public: @@ -171,6 +193,13 @@ namespace mongo { RegistrationAgent(const std::string& suiteName, const std::string& testName); }; + /** + * This exception class is used to exercise the testing framework itself. If a test + * case throws it, the framework would not consider it an error. + */ + class FixtureExceptionForTesting : public std::exception { + }; + private: /** * Called on the test object before running the test. |