有没有办法模拟QSqlQuery
Is there a way to mock QSqlQuery?
我最近才发现了gmock,现在正在"重新思考整个编程过程",尽可能地添加单元测试。在这个过程中,让我感到奇怪的一件事是,QSql 模块显然是我们代码的外部依赖项,没有为开发人员提供模拟其内部的工具。我能想到的最好的东西是内存数据库,它比简单的模拟更难实现,甚至并不总是可能的(考虑使用内存数据库伪造预言机包)
现在,对我来说,这不是一个问题,不久前我们已经切换到从虚拟接口继承的本土 ocilib 包装器(因此很容易被嘲笑)。但真的,当你使用Qt自己的QSql模块时,是不是没有办法嘲笑?或者更确切地说 - Qt 是一个(非常好的)框架,它们真的没有为此类用例提供自动化还是我错过了什么?
UPD1:关于问题重要性的小更新:
我的代码与Oracle SQL查询交错在一起,当然,这是许多其他人的代码。 当外部依赖项(也在大量开发中)有时会提供不正确的数据时,对此类代码进行单元测试几乎是不可能的。当你的单元测试中断时,你希望出错的是你的代码,而不是 Oracle。这就是我问原始问题的原因。如果存在/存在一种使用 qsqlquery 接口半轻松模拟依赖关系的方法,那么使用 QSql 为代码编写单元测试成为可能。
UPD2:虽然,经过进一步的考虑,我不得不承认,这个问题可以通过更好的代码设计(在某些地方使用OO而不是自由函数)和更好的实体分离来避免。因此,在UPD1中几乎不可能并不是真正合理的。虽然这并没有真正使原始问题变得不那么重要。例如,当你的任务是维护遗留代码时,模拟QtSql是将测试引入系统的唯一现实方法。
Zeks,IMO 你有 2 种方法来模拟 Qt Sql 类:
- 子类化Qt Sql类;
- 围绕Qt Sql类的包装器并通过接口传递它们。
方法#1:
一般来说是痛苦。首先,如果你想模拟QSqlQuery,你必须为QSqlResult,QSqlDriver和QSqlQuery本身创建子类。然后,另一个痛苦出现在游戏中,你必须设置前提条件 - 例如:你希望你的sql在调用exec()函数时返回true,为此,你的QSqlDriver子类必须返回:
class QSqlDriverTest : public QSqlDriver
{
...
virtual bool isOpen() const { return true; }
virtual void setOpenError(bool e) { QSqlDriver::setOpenError(false); }
...
};
这只是一个例子。成功调用 next() 函数还有更多先决条件。要找出它们,您始终需要查看qt源代码。所以这完全取决于qt。此方法失败,因为:
- 这并不容易 - 单元测试必须容易;
- 您仍然有 Qt 依赖项;
方法#2:
我认为这是模拟查询的最佳和清晰方法,但您需要准备代码。创建一个接口 ISQLQuery,它具有与 QSqlQuery 相同的功能(QSqlDriver 和 QSqlResult 相同)。喜欢这个:
class ISQLQuery // interface wrapper for QSqlQuery
{
public:
~ISQLQuery(){}
...
virtual bool exec() = 0;
virtual QVariant value(int i) const = 0;
virtual const ISQLDriver * driver() const = 0;
...
};
class ISQLDriver // interface wrapper for QSqlDriver
{
public:
~ISQLDriver(){}
...
virtual bool subscribeToNotification(const QString & name) = 0;
...
};
然后你创建真正的实现(这只是草稿想法):
class SQLDriver : public ISQLDriver
{
public:
SQLDriver(const QSqlDriver * driver) : mpDriver(driver){}
...
virtual bool subscribeToNotification(const QString & name)
{ return mpDriver->subscribeToNotification(name); }
...
private:
const QSqlDriver * mpDriver;
};
class SQLQuery : public ISQLQuery
{
public:
SQLQuery(): mDriver(mQuery->driver){}
...
virtual bool exec() { return mQuery.exec(); }
virtual QVariant value(int i) const { return mQuery.value(i); }
virtual const SQLDriver * driver() const { return &mDriver; }
...
private:
QSqlQuery mQuery;
SQLDriver mDriver;
...
};
有一个示例,当创建和实现所有接口时如何使用新的sql类:
// some function
{
...
SQLQuery query = SQLFactory::createSQLQuery(); // here you can put your mocks
query.prepare("DROP TABLE table_hell;");
query.exec();
...
}
我已经向您展示了主要思想,没有所有细节,否则帖子可能会变得很大。我希望你会发现我的解释有用。
问候。
如果你只想将内存中的SQL数据库用作QtSQL的模拟后端,你可以考虑使用SQLite。
在SQLite 是一个进程内库,它实现一个独立的、无服务器的、零配置的事务性 SQL 数据库引擎。SQLite的代码属于公共领域,因此可以免费用于任何目的,商业或私人目的。SQLite是世界上部署最广泛的数据库,其应用程序数量超出了我们的数量,包括几个备受瞩目的项目。
QtSQL 调用背后使用真正的 SQL 解释器的优点是,您可以验证传入的 SQL 语法,以及查询是否实际返回预期结果。
如果您关心的是测试执行 Oracle SQL 特定功能的 SQL 查询,那么没有其他方法可以知道您是否正确使用了这些功能,而无需针对真正的 Oracle SQL 服务器进行测试。
- 如何使用Google Mock来模拟gettimeofday()
- QSqlquery prepare()和bindvalue()不工作
- G锁定铸造到基础上会释放模拟行为
- 有什么好的方法可以让系统调用代理允许在单元测试中进行模拟
- 落砂模拟碰撞检测C++和SFML
- 在gtest.中使用fff.h模拟系统API
- 谷歌模拟和覆盖关键字
- 用C#中的并集模拟C++嵌套结构
- 在同一模拟中使用静脉和静脉_ inet内容时出现运行时错误
- 在模拟器中使用并集来模拟CPU寄存器有多合适
- 我写了一个C++程序来模拟Enigma机器.我没有得到输出
- 如何模拟不同边数的骰子滚动?
- 模拟持久按键
- 使用SIR模型的疾病爆发模拟
- 在 c++ 中模拟输入并在 JAVA 中读取它?
- 转发变量参数列表以模拟 std::thread
- 如何在谷歌模拟中匹配 C 样式数组
- 如何使用兰德随机化模拟点击
- 模拟GPS数据,以便使用Qt与Traccar一起使用
- 有没有办法模拟QSqlQuery