我刚刚发现了gmock,现在我正在重新思考整个编程过程,因为它是",尽我所能添加单元测试。 令我觉得奇怪的是,在这个过程中,QSql模块明显是我们代码的外部依赖,并没有给开发人员提供模拟其内部的工具。我能用这个模块想到的最好的东西是内存数据库,它比简单的模拟更难实现,甚至不可能(考虑使用内存数据库伪造oracle包)
现在,对我来说,这不是一个问题,前一段时间我们已经切换到继承自虚拟接口的本地增长的ocilib包装器(因此,很容易模拟)。但是真的,当你使用Qt自己的QSql模块时,有没有办法嘲笑?或者更确切地说 - Qt是一个(非常好的)框架,他们真的没有为这些用例提供自动化,或者我错过了什么?
UPD1: 关于问题重要性的小更新:
我的代码与Oracle SQL查询非常交错,对于某些其他人的代码而言。当外部依赖(也是大量开发)有时会提供不正确的数据时,单元测试这样的代码实际上是不可能的。当您的单元测试中断时,您希望它是您的代码,而不是Oracle。这就是我问原问题的原因。如果存在/存在使用qsqlquery接口半容易地模拟依赖关系的方法,则可以使用QSql编写代码的单元测试。
UPD2:虽然在进一步考虑之后,我不得不承认,通过更好的代码设计(OO而不是某些地方的免费功能)和更好的实体分离可以避免这个问题。因此,UPD1中的几乎不可能并不合理。虽然这并不能使原始问题变得不那么重要。例如,当你负责维护遗留代码时,模拟QtSql是将测试引入系统的唯一现实方法。答案 0 :(得分:1)
如果您只想将内存中的SQL数据库用作QtSQL的模拟后端,可以考虑使用SQLite。
SQLite是一个进程内库,它实现了一个独立的,无服务器,零配置的事务SQL数据库引擎。 SQLite的代码属于公共领域,因此可以免费用于任何目的,商业或私人。 SQLite是世界上部署最广泛的数据库,其应用程序数量超出我们的数量,包括几个备受瞩目的项目。
在QtSQL调用背后使用真正的SQL解释器的优点是,您可以验证传入的SQL语法,以及查询是否实际返回预期结果。
如果您关注的是测试执行Oracle SQL特定功能的SQL查询,那么没有其他方法可以知道您正在使用这些功能而无需针对真正的Oracle SQL服务器进行测试。
答案 1 :(得分:1)
Zeks,IMO你有两种模拟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。这种方法失败的原因是:
方法#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();
...
}
我已经向你展示了没有所有细节的主要想法,否则帖子可能变得庞大。我希望你会发现我的解释很有用。
问候。