Я пытаюсь протестировать конкретный объект с такой структурой.
class Database {
public:
Database(Server server) : server_(server) {}
int Query(const char* expression) {
server_.Connect();
return server_.ExecuteQuery();
}
private:
Server server_;
};
т.е. у него нет виртуальных функций, не говоря уже о четко определенном интерфейсе.
Я хочу создать поддельную базу данных, которая вызывает фиктивные сервисы для тестирования. Хуже того, я хочу, чтобы один и тот же код создавался либо для реальной версии, либо для подделки, чтобы один и тот же код тестирования мог одновременно:
- Проверка реальной реализации базы данных - для интеграционных тестов
- Проверка фальшивой реализации, которая вызывает фиктивные сервисы
Чтобы решить эту проблему, я использую шаблонную подделку, например:
#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_;
};
Редактировать: Обратите внимание, что поддельная база данных должна вызывать реальную базу данных (но с поддельным сервером).
Теперь для переключения между ними я планирую следующую тестовую среду:
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;
}
};
Я не большой поклонник того переключения во время компиляции между реальным и фальшивым.
Итак, мой вопрос:
- Есть ли лучший способ переключения между базой данных и FakeDatabase? Например, возможно ли сделать это во время выполнения чистым способом? Мне нравится избегать # ifdefs.
- Кроме того, если у кого-то есть лучший способ создать поддельный класс, имитирующий конкретный класс, я был бы признателен за это.
Я не хочу иметь шаблонный код по всему фактическому тестовому коду (класс QueryTestCase).
Не стесняйтесь критиковать и сам стиль кода. Вы можете увидеть скомпилированную версию этого кода на кодовой панели .