summaryrefslogtreecommitdiff
path: root/src/mongo/unittest
diff options
context:
space:
mode:
authorAlberto Lerner <alberto.lerner@gmail.com>2012-06-18 10:06:30 -0400
committerAlberto Lerner <alberto.lerner@gmail.com>2012-06-27 13:37:56 -0400
commit24fddec0622f7814652c4b9c4c3189ad1089d567 (patch)
tree274d6cb5c5d871b063318459acf1498aad9aab24 /src/mongo/unittest
parentc35804c9e9ad55511b27eb7b30af8e89902f2eb2 (diff)
downloadmongo-24fddec0622f7814652c4b9c4c3189ad1089d567.tar.gz
Added fixtures to new unit test framework.
Here's how this take on fixtures with exception handling works: (Basically, setUp/tearDown mimic the expectations we have for constructors/ destructors in our coding guidelines.) + If the fixture throws on setUp() (for instance, because of an ASSERT), then that test case would be considered failed and tearDown() would not run. The remainder of the test suite should run fine, assuming calling setUp again in each test case would build the fixture properly. + If the test body code throws because of an ASSERT, then tearDown() will be issued and the test case would be considered failed. The remainder of the suite should run fine. + If the test body code throws an unexpected assertion, then tearDown() will NOT run and the entire suite is compromised. + tearDown() should be treated as a destructor and therefore should not throw.
Diffstat (limited to 'src/mongo/unittest')
-rw-r--r--src/mongo/unittest/SConscript2
-rw-r--r--src/mongo/unittest/fixture_test.cpp88
-rw-r--r--src/mongo/unittest/unittest.cpp18
-rw-r--r--src/mongo/unittest/unittest.h39
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.