J'ai précédemment posé cette question sous un autre nom mais l'a supprimé parce que je ne l'ai pas très expliqué.
Disons que j'ai une classe qui gère un fichier. Disons que cette classe traite le fichier comme ayant un format de fichier spécifique et contient des méthodes pour effectuer des opérations sur ce fichier: p> disons que j'aimerais pouvoir être capable de pouvoir Unité teste la partie de cette classe qui calcule la somme de contrôle. Test de l'unité Les parties de la classe qui se chargent dans le fichier et telle sont irréalistes, car pour tester chaque partie de la méthode désormais désormais tester le test Est-ce que quelqu'un connaît une solution à ce problème? P> p> getChecksum () code> Je devrais construire 40 ou 50 fichiers! P> < P> Permet de dire que je voudrais réutiliser la méthode de la somme de contrôle ailleurs dans la classe. J'extraire la méthode de sorte qu'elle ressemble à ceci: p>
Calculatechecksum () code> méthode car c'est facile Pour tester et compliquer, et je me fiche de tester unitaire
getChecksum () code> car il est simple et très difficile à tester. Mais je ne peux pas tester
calculatechecksum () code> directement car il est
privé code>. P>
6 Réponses :
La réponse directe simple consiste à rendre votre classe de test d'unité un ami de la classe à tester. De cette façon, la classe de test de l'unité peut accéder à Une autre possibilité de regarder est que FOO semble avoir un certain nombre de responsabilités non liées et pourrait être dû à la ré-factorisation. Tout à fait, calculer une somme de contrôle ne doit pas vraiment faire partie de calculatechecksum () code> même s'il est privé. P>
foo code> du tout. Au lieu de cela, le calcul de la somme de contrôle peut être mieux éteint comme algorithme à usage général que quiconque puisse s'appliquer au besoin (ou éventuellement, une sorte d'inverse - un foncteur à utiliser avec un autre algorithme comme
std :: accumuler code>) . P>
+1 J'aime cette idée ... Y a-t-il un moyen de le faire avec Boost :: Test?
@Billyonéal: Vous feriez probablement mieux de demander cela comme une question distincte - hors tension, je ne suis pas sûr, mais quelqu'un d'autre (qui est moins susceptible de voir ces commentaires) très bien pourrait bien.
Fondamentalement, on dirait que vous voulez un Mock pour effectuer des tests d'unité plus réalisables. La façon dont vous rendez une classe ciblable pour les tests d'unités de manière autonome de la hiérarchie de l'objet et des dépendances externes est via Injection de dépendance . Créez une classe "FOOFilerReader" Comme: Foo(FooFileReader* pReader)
+1 Je suppose que cela pourrait fonctionner pour ce scénario spécifique - mais j'espère une réponse plus générale qui fonctionnerait pour tout type de classe de gestion des ressources, une clé de registre, un fichier, une pipe, etc. désolé je n'étais pas assez clair dans la question :(
Une manière d'extraire la méthode de la somme de contrôle dans sa propre classe et d'avoir une interface publique avec laquelle tester. p>
Comment ça va mieux que de faire la méthode de la somme de contrôle publique code> en premier lieu?
Bien sûr, vous ne voudriez pas que la checksum soit publique à FOO; Cela ne correspond pas à l'interface de la classe. Ma pensée était que ce n'est vraiment pas la responsabilité de FOO de calculer la somme de contrôle et qu'elle devrait être retirée de sa propre classe. Ayant fait cela, vous le testez de la même manière que vous l'utiliseriez de FOO.
Je commencerais en extrayant le code de calcul de la somme de contrôle dans sa propre classe: Cela facilite la test du calcul de la somme de contrôle en isolement. Vous pouvez cependant le prendre une étape plus loin et créer une interface simple: p> et la mise en oeuvre: p> puis Passez l'interface dans votre code de production réel, vous créeriez un maintenant, même si filecalculator code> à votre
FOO code> constructeur: p>
CheckSumCalculator code> et transmettez-le sur
FOO code>, mais dans votre code de test de l'unité, vous pouvez créer un
faux_checksumcalculator code> (qui, par exemple, a toujours renvoyé une somme de contrôle prédéfinie). p>
foo code> a une dépendance sur
checksumcalculator code>, vous pouvez construire et tester ces deux classes en isolement complet. P> < / p>
Oui, je suppose que cela fonctionne, mais cela ne casse-t-il pas tout le point de faire le calcul de la somme de contrôle privé code> en premier lieu? Il semble que cela soit un moyen très rond-point de faire la fonction publique. Comment cela améliore-t-il l'encapsulation sur une fonction publique?
Billyonéal: privé code> protège les données, les opérations sans données sont sans faute et n'ont besoin de protection.
Si je devais choisir un compromis de design, je préférerais beaucoup avoir des classes plus petites pouvant être instanciées et testées indépendamment dans un harnais de test et des classes plus grandes avec de nombreuses méthodes code> de code> difficiles à tester. Cela peut signifier que certaines des «fonctionnements intérieurs» de votre bibliothèque sont désormais exposés au monde, mais si le résultat est un code mieux testé, cela vaut généralement la peine.
#ifdef TEST #define private public #endif // access whatever you'd like to test here
Si le code de test et le code réel ont été compilés ensemble, cela fonctionnerait. Malheureusement, le code que je teste est dans une bibliothèque statique et les tests de l'unité sont dans une .exe .exe. :(
Cela n'a pas d'importance. L'accès privé / public n'est appliqué que par le compilateur et n'existe pas dans le temps d'exécution. Donc, cela fonctionnerait exactement le même. Utilisez simplement cette définition avant l'inclusion de l'en-tête que vous utilisez et que vous êtes tous définis.
Au moins, ça va généralement i> travail. En théorie, le compilateur serait libre de faire des choses, de sorte que ce n'est pas cependant. N'importe où il y a un spécificateur d'accès, il est autorisé à réorganiser l'ordre des éléments en mémoire, de sorte qu'il pourrait, par exemple, mettre tous les éléments publics ensemble, puis tous les protégés et enfin tous les privés. C'est surtout théorique cependant ...
Bien la manière préférée en C ++ pour le fichier IO est par flux. Donc, dans l'exemple ci-dessus, il serait peut-être beaucoup plus de sens pour injecter un flux au lieu d'un nom de fichier. Par exemple, de cette façon, vous pouvez utiliser Si vous ne souhaitez pas utiliser de flux, l'exemple standard d'un motif RAII définissant un fichier std :: stringstream code> pour tester l'unité et avoir le contrôle total du test. P>
fichier code> peut être utilisé. Le moyen "simple" de procéder est de créer une classe d'interface virtuelle pure
fichier code>, puis une implémentation de l'interface. La classe
FOO code> utiliserait ensuite le fichier de classe d'interface. Par exemple, P>
FileImple(const FileHandler& fileHandler, const std::string& fileName) :
mFileHandler(fileHandler), mFileName(fileName)