6
votes

Test de l'unité Méthode privée dans la classe de gestion des ressources (C ++)

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: xxx

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 getChecksum () Je devrais construire 40 ou 50 fichiers! < 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: xxx

désormais désormais tester le test Calculatechecksum () méthode car c'est facile Pour tester et compliquer, et je me fiche de tester unitaire getChecksum () car il est simple et très difficile à tester. Mais je ne peux pas tester calculatechecksum () directement car il est privé .

Est-ce que quelqu'un connaît une solution à ce problème?


0 commentaires

6 Réponses :


1
votes

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 à calculatechecksum () même s'il est privé.

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 foo 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 ) .


2 commentaires

+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.



2
votes

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 commentaires

+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 :(



3
votes

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.


2 commentaires

Comment ça va mieux que de faire la méthode de la somme de contrôle publique 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.



1
votes

Je commencerais en extrayant le code de calcul de la somme de contrôle dans sa propre classe: xxx

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: xxx

et la mise en oeuvre: xxx

puis Passez l'interface filecalculator à votre FOO constructeur: xxx

dans votre code de production réel, vous créeriez un CheckSumCalculator et transmettez-le sur FOO , mais dans votre code de test de l'unité, vous pouvez créer un faux_checksumcalculator (qui, par exemple, a toujours renvoyé une somme de contrôle prédéfinie).

maintenant, même si foo a une dépendance sur checksumcalculator , vous pouvez construire et tester ces deux classes en isolement complet. < / p>


3 commentaires

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é 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é 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 de 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.



1
votes
#ifdef TEST
#define private public
#endif

// access whatever you'd like to test here

3 commentaires

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



0
votes

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, xxx pré>

de cette façon, vous pouvez utiliser std :: stringstream code> pour tester l'unité et avoir le contrôle total du test. P>

Si vous ne souhaitez pas utiliser de flux, l'exemple standard d'un motif RAII définissant un fichier 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)


0 commentaires