Y a-t-il un moyen de se moquer de QSqlQuery?

je viens de découvrir gmock et je suis en train de "repenser l'ensemble du processus de programmation tel qu'il est", ajoutant des tests unitaires partout où je peux. Une chose qui m'a frappé comme étrange dans le processus est que le module QSql étant clairement une dépendance externe à notre code, ne donne pas aux développeurs des outils pour se moquer de ses internes. La meilleure chose à laquelle je peux penser avec ce module est in-memory DB qui est beaucoup plus difficile à mettre en œuvre qu'un simple mock et n'est même pas toujours possible (envisager la simulation packages oracle avec en mémoire DB)

maintenant, pour moi, ce n'est pas exactement un problème, il y a un moment nous avons opté pour ocilib wraper maison qui hérite de l'interface virtuelle (et est, donc, facilement moquable). Mais vraiment, n'y a-t-il aucun moyen de se moquer lorsque vous utilisez le module QSql de Qt? Ou plutôt-Qt étant un (vraiment bon) cadre, est-ce qu'ils ne fournissent vraiment aucune automatisation pour de tels cas d'utilisation ou est-ce que je manque quelque chose?

UPD1: Une petite mise à jour sur l'importance du question:

mon code est très fortement interféré avec les requêtes SQL D'Oracle comme, pour certains, le code de beaucoup d'autres personnes. La mise à l'essai d'un tel code à l'unité est pratiquement impossible lorsqu'une dépendance externe, qui est aussi fortement en développement, fournit parfois des données inexactes. Lorsque le test de votre unité est interrompu, vous voulez que ce soit votre code qui soit en cause, pas Oracle. C'est pourquoi j'ai demandé à la question d'origine. S'il existe/existait un moyen de se moquer à moitié facilement de la dépendance en utilisant qsqlquery interface alors l'écriture de tests unitaires pour le code en utilisant QSql devient possible.

UPD2: bien que, après un examen plus approfondi, je dois admettre que le problème pourrait être évité avec une meilleure conception du code (OO au lieu de fonctions libres à certains endroits) et une meilleure séparation des entités. Donc, virtuellement impossible dans UPD1 n'était pas vraiment justifié. Mais cela ne rend pas la question originale moins importante. Lorsque vous êtes chargé de maintenir le code d'héritage, par exemple, se moquer de QtSql c'est la seule façon réaliste d'introduire des tests dans le système.

19
demandé sur Zeks 2015-06-18 03:16:25

2 réponses

si vous voulez simplement qu'une base de données SQL en mémoire soit utilisée comme un backend mock pour QtSQL, vous pouvez envisager d'utiliser SQLite.

SQLite est une bibliothèque en processus qui implémente un moteur de base de données SQL autonome, sans serveur, à configuration zéro, transactionnelle. Le code pour SQLite est dans le domaine public et est donc libre pour une utilisation à toute fin, commerciale ou privée. SQLite est la base de données la plus largement déployée dans le monde avec plus d'applications que nous pouvons compte, y compris plusieurs projets très médiatisés.

l'avantage d'utiliser un véritable interpréteur SQL derrière les appels QtSQL est que vous pouvez valider la syntaxe SQL transmise, et si la requête renvoie réellement le résultat attendu.

si votre préoccupation est de tester les requêtes SQL qui utilisent des fonctionnalités spécifiques à Oracle SQL, alors il n'y a pas d'autre moyen de savoir que vous utilisez ces fonctionnalités correctement sans tester un vrai serveur Oracle SQL.

1
répondu jxh 2015-06-27 01:58:27

Zeks de l'OMI, vous avez 2 méthodes pour se moquer de Qt Sql classes:

  1. sous-classement Qt Sql classes;
  2. enrouler autour des classes Sql Qt et les passer à travers les interfaces.

Approche #1:

généralement c'est de la douleur. Tout d'abord, si vous voulez vous moquer de QSqlQuery, vous devez créer des sous-classes pour QSqlResult, QSqlDriver et QSqlQuery lui-même. Ensuite, une autre douleur vient dans le jeu, vous devez définir conditions préalables-par exemple: vous voulez que votre sql renvoie true lors de l'appel de la fonction exec (), pour cela, votre sous-classe de QSqlDriver doit revenir:

class QSqlDriverTest : public QSqlDriver
{
   ...
   virtual bool isOpen() const { return true; }
   virtual void setOpenError(bool e) { QSqlDriver::setOpenError(false); }
   ...
};

ce n'est qu'un exemple. Il y a encore plus de conditions préalables pour appeler la fonction next() avec succès. Pour les trouver, vous devez toujours regarder dans le code source qt. Cela dépend donc entièrement de qt. Cette approche échoue parce que:

  • il n'est pas facile - test unitaire doit être facile;
  • vous ont toujours une dépendance qt;

Approche #2:

je pense que c'est la meilleure façon de simuler des requêtes, mais vous devez préparer votre code. Vous créez une interface ISQLQuery qui a les mêmes fonctions que QSqlQuery (la même chose pour QSqlDriver et QSqlResult). Comme ceci:

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;
   ...
};

puis vous créez des implémentations réelles (c'est juste une ébauche d'idée):

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;
   ...
};

il y a un exemple d'utilisation de nouvelles classes sql, quand toutes les interfaces sont créées et mises en œuvre:

// some function
{
   ...
   SQLQuery query = SQLFactory::createSQLQuery();   // here you can put your mocks
   query.prepare("DROP TABLE table_hell;");
   query.exec();
   ...
}

je vous ai montré l'idée principale sans tous les détails sinon la poste pourrait devenir énorme. J'espère que vous trouverez mon explication utile.

Cordialement.

1
répondu GrauerHase 2017-05-23 12:16:09