Les tests unitaires destructeurs?
Est-il un bon moyen de test de l'unité destructeurs? Comme, disons, j'ai une classe comme ceci (fictive) exemple:
class X
{
private:
int *x;
public:
X()
{
x = new int;
}
~X()
{
delete x;
}
int *getX() {return x;}
const int *getX() const {return x;}
};
Est-il un bon moyen de l'unité de tester pour vous assurer que x est supprimé sans encombrer mon fichier php avec #ifdef TESTs ou de briser l'encapsulation? Le principal problème que je vois, c'est qu'il est difficile de dire si x est vraiment a été supprimé, en particulier parce que l'objet est hors de portée à la fois le destructeur est appelé.
OriginalL'auteur Jason Baker | 2008-11-23
Vous devez vous connecter pour publier un commentaire.
Il y a peut être quelque chose à dire pour l'injection de dépendance. Au lieu de créer un objet (dans ce cas un int, mais dans un non-artificiel cas plus probable d'un type défini par l'utilisateur) dans son constructeur, l'objet est passé en paramètre au constructeur. Si l'objet est créé plus tard, puis une usine est transmis au constructeur de X.
Puis, lorsque vous êtes de tests unitaires, vous passez dans un simulacre de l'objet (ou une maquette de l'usine qui crée les objets fantaisie), et le destructeur enregistre le fait qu'il a été appelé. Le test échoue si elle ne l'est pas.
Bien sûr, vous ne pouvez pas se moquer (ou remplacer) d'une interface de type, de sorte que dans ce cas particulier, il n'est pas bon, mais si vous définissez l'objet d'usine/avec une interface alors vous pouvez.
Vérifier pour les fuites de mémoire dans les tests unitaires peuvent souvent être fait à un niveau plus élevé, comme d'autres l'ont dit. Mais qui vérifie seulement que un destructeur est appelé, il ne prouve pas que le droit destructeur a été appelé. Donc il ne serait pas par exemple attraper un manque de "virtuel" déclaration sur le destructeur de la nature de x membre (encore une fois, ne sont pas pertinentes si c'est juste un int).
Yep, et à peu près exactement le même temps. Je suppose que j'ai gagné parce que vous avez cessé d'écrire un exemple de code 🙂
OriginalL'auteur Steve Jessop
Je pense que votre problème est que votre exemple n'est pas testable. Puisque vous voulez savoir si
x
a été supprimé, vous avez vraiment besoin pour être en mesure de remplacerx
avec un simulacre. C'est sans doute un peu OTT pour un int, mais je suppose que dans votre exemple vous avez quelques autres de la classe. Pour rendre testable, leX
constructeur doit demander à l'objet de la mise en œuvre de laint
interface:Maintenant, il devient très simple de se moquer de la valeur pour
x
, et la fantaisie peut gérer la vérification de la correcte destruction.S'il vous plaît prêter aucune attention aux gens qui disent que vous devez casser l'encapsulation ou le recours à l'horrible hacks pour conséquence de code de tests. S'il est vrai que le code testé est mieux que du code non testé, de code de tests est le meilleur de tous et il en résulte toujours dans le code plus clair avec moins de hacks et plus faible couplage.
Rappelez-vous, peut-être que je suis juste de mauvaise humeur parce que j'ai dit, vous ne pouvez pas se moquer d'une interface de type, qui comme vous l'avez souligné, c'est faux, parce que vous pouvez le faire de cette façon, à l'aide de modèles et d'une classe qui implémente l'ensemble de l'int de l'interface (pas trivial, mais vous ne devez le faire qu'une fois. N'oubliez pas numeric_limits).
Eh bien, vous n'auriez pas à faire templatised. Si vous avez supprimé le modèle et changé de T int partout dans mon exemple, il serait encore être testable
OriginalL'auteur 1800 INFORMATION
J'ai tendance à aller avec un "Par tous les moyens nécessaires" méthode de test. Si elle a besoin d'un test, je suis prêt à la fuite d'abstractions, de briser l'encapsulation, et hack... parce que code testé est mieux que assez de code. Je vais souvent le nom de l'méthodes de briser ce quelque chose comme VaildateForTesting ou OverrideForTesting pour le rendre clair que la violation de l'encapsulation est destinée à des fins de test.
Je ne connais pas d'autre façon de le faire en C++ que d'avoir le destructeur appel dans un singleton pour vous inscrire qu'il a été détruit. J'ai trouvé une méthode pour faire quelque chose de similaire à ceci en C# à l'aide d'une référence faible (je n'ai pas violer l'encapsulation ou des abstractions avec cette approche). Je ne suis pas assez créatifs pour trouver une analogie avec le C++, mais VOUS pourriez être. Si cela peut aider, tant mieux, sinon, désolé.
http://houseofbilz.com/archive/2008/11/11/writing-tests-to-catch-memory-leaks-in-.net.aspx
OriginalL'auteur Brian Genisio
Dans l'exemple, de définir et de instrument votre global new et delete.
Pour éviter de #ifdefs, j'ai faire des classes de test amis. Vous pouvez définir/sauver/récupérer l'état nécessaires pour vérifier les résultats d'un appel.
Je ne sais pas ce que l'homme de paille de votre imagination. L'instrumentation est destiné à répondre à des questions comme "x est toujours allouée"? D'autres réponses ici de profiter d'une plate-forme de la version spécifique de la mémoire de l'instrumentation plutôt que de prendre le contrôle de vous-même.
Votre design est un pauvre. Pourquoi devriez-vous modifier vos classes en cours de test afin que votre harnais de test peut travailler avec elle? Si vous faites vos classes tesable depuis le début (voir mon exemple), vous n'avez pas besoin de recourir à de telles choses
Votre reste à imaginer quelque chose que je n'ai pas dit.
Vous avez dit "j'ai du faire des classes de test amis" - c'est la modification de la classe sous test dans le but de faire votre test faisceau de travailler avec elle. Vous ne devriez pas avoir à le faire.
OriginalL'auteur Tony Lee
Il ne sera pas pertinent pour le gars qui a posé la question, mais peut-être utile à d'autres personnes qui liront ce. M'a posé une question similaire, dans une entrevue d'emploi.
En supposant que la mémoire est limitée, vous pouvez essayer cette méthode:
si vous pouvez allouer exactement la même mémoire que vous parvenez à allouer avant d'exécuter le test, le destructeur fonctionne très bien.
Cette méthode fonctionne (raisonnablement) lorsque vous avez de petits limitée de la mémoire, sinon, il paraît déraisonnable, au moins à mon avis.
OriginalL'auteur Itay Gal
Certains compilateurs écrasera supprimé de la mémoire avec un modèle connu dans le mode de débogage pour les aider à détecter les accès à balançant des pointeurs. Je sais que Visual C++ pour utiliser le 0xDD, mais je ne l'ai pas utilisé depuis un moment.
Dans votre cas de test, vous pouvez stocker une copie de x, le laisser aller hors de portée et assurez-vous que *x == 0xDDDDDDDD:
Je suis d'accord que c'est pas génial pour les raisons que vous avez mentionnées, et vous ne pouvez pas accès privé pointeurs. En général, je pense que votre idée (et onebyone) est mieux, mais ce n'est pas toujours trivial d'utiliser un objet fantaisie.
OriginalL'auteur Matthew Crumley
Pas une plate-forme agnostique suggestion, mais dans le passé j'ai fait des appels dans le CRT de la vérification des tas de fonctions au cours de l'unité de test, pour vérifier qu'il n'y a pas plus de mémoire allouée à la fin d'un test (ou peut-être un ensemble de tests) que le début. Vous pourriez également être en mesure de faire quelque chose de similaire avec votre plate-forme d'instrumentation, à vérifier sur la poignée-compte, etc.
OriginalL'auteur Will Dean