views:

137

answers:

3

I'm trying to testing a concrete object with this sort of structure.

class Database {
 public:
  Database(Server server) : server_(server) {}
  int Query(const char* expression) {
    server_.Connect();
    return server_.ExecuteQuery();
  }

 private:
  Server server_;
};

i.e. it has no virtual functions, let alone a well-defined interface.

I want to a fake database which calls mock services for testing. Even worse, I want the same code to be either built against the real version or the fake so that the same testing code can both:

  • Test the real Database implementation - for integration tests
  • Test the fake implementation, which calls mock services

To solve this, I'm using a templated fake, like this:

#ifndef INTEGRATION_TESTS
class FakeDatabase {
 public:
  FakeDatabase() : realDb_(mockServer_) {}
  int Query(const char* expression) {
    MOCK_EXPECT_CALL(mockServer_, Query, 3);
    return realDb_.Query();
  }
private:
  // in non-INTEGRATION_TESTS builds, Server is a mock Server with
  // extra testing methods that allows mocking
  Server mockServer_;
  Database realDb_;
};
#endif

template <class T>
class TestDatabaseContainer {
 public:
  int Query(const char* expression) {
    int result = database_.Query(expression);
    std::cout << "LOG: " << result << endl;
    return result; 
  }
private:
  T database_;
};

Edit: Note the fake Database must call the real Database (but with a mock Server).

Now to switch between them I'm planning the following test framework:

class DatabaseTests {
 public:
#ifdef INTEGRATION_TESTS
  typedef TestDatabaseContainer<Database> TestDatabase ;
#else
  typedef TestDatabaseContainer<FakeDatabase> TestDatabase ;
#endif

  TestDatabase& GetDb() { return _testDatabase; }

 private: 
  TestDatabase _testDatabase;
};

class QueryTestCase : public DatabaseTests {
 public:
  void TestStep1() {
    ASSERT(GetDb().Query(static_cast<const char *>("")) == 3);
    return;
  }
};

I'm not a big fan of that compile-time switching between the real and the fake.

So, my question is:

  1. Whether there's a better way of switching between Database and FakeDatabase? For instance, is it possible to do it at runtime in a clean fashion? I like to avoid #ifdefs.
  2. Also, if anyone has a better way of making a fake class that mimics a concrete class, I'd appreciate it.

I don't want to have templated code all over the actual test code (QueryTestCase class).

Feel free to critique the code style itself, too. You can see a compiled version of this code on codepad.

A: 

You could put the tested code and the mock/fake in their own source files. You could then link with whichever version you wanted to use.

I personally don't put my testing code in with my production code. It's a separate project.

Jay
They are in separate files.That fact doesn't help me as the problem with compiling/linking against separate test and production Database code is that the fake calls the real Database. I've updated the question to make this clearer.
AshirusNW
A: 

If you want to choose between implementation of database during runtime, then apparently you need runtime polymorphism instead of static polymorphism. So change template class TestDatabaseContainer that relies on the concept "Database" to regular class that relies on the interface "Database" and let FakeDatabase and real Database inherit that interface:

class IDatabase
{
public:
    int Query(const char* expression) = 0;
};
class TestDatabaseContainer 
{
 public:
  TestDatabaseContainer(IDatabase& d) : database_(d) {}
  int Query(const char* expression) {
    int result = database_.Query(expression);
    std::cout << "LOG: " << result << endl;
    return result; 
  }
private:
  IDatabase& database_;
};
class DatabaseTests 
{
 public:
  TestDatabaseContainer GetDb() 
  { 
      if(IntegrationTests)
          return TestDatabaseContainer(*(new Database));
      else 
          return TestDatabaseContainer(*(new FakeDatabase)); 
  }
};

(I'm in no way responsible for any memory leaked :) so modify it appropriately)

Alsk
Unfortuantly, I can't modify the existing Database class.
AshirusNW
then let the FakeDatabase inherit the Database and use "Database" type, instead of "IDatabase"
Alsk
Aye but Database doesn't have any virtual methods so callers to "Database* pDb = new FakeDatabase" will always call the real one
AshirusNW
right, overlooked that, my bad
Alsk
added another answer
Alsk
A: 

In case the database has no virtual functions:

//ancestor of database containers
class TestDatabase
{
public:
  virtual int Query(const char* expression) = 0;
}; 
//TestDatabaseContainer is the same as in the example, but
//inherits TestDatabase
template <class T>
class TestDatabaseContainer: public TestDatabase
{
//...
};
class DatabaseTests 
{
 public:
  TestDatabase* GetDb() 
  { 
      if(IntegrationTests)
          return new TestDatabaseContainer<Database>();
      else 
          return new TestDatabaseContainer<FakeDatabase>();
  }
  //...
};
Alsk
This won't work: TestDatabase* GetDb()The TestDatabase you've created is simply a interface which I can't retrofit onto the Database class
AshirusNW