2017-09-22 5 views
3

Commençons par un exemple de travail minimal:
main.cpp:supprimer le code d'exception généré automatique du rapport de couverture

#include <iostream> 
#include <string> 

int main() { 
    std::cout << "hello " + std::to_string(42); 
    return 0; 
} 

Je compile ce code en utilisant les drapeaux suivants:

[g++/clang++] -std=c++11 -g -Og --coverage -Wall -o main main.cpp 

Clang 4.0.1
gcc 4.8.5.

Je reçois seulement 50% de couverture de code, puisque le compilateur génère du code d'exception, qui n'est pas exécuté, comme expliqué in another stackoverflow question.

Le problème est que la désactivation des exceptions via -fno-exceptions n'est pas une option pour moi. Le code que j'écris pour les tests unitaires utilise des exceptions, donc la désactivation de tous n'est pas une option.

Afin de générer un rapport j'utilise gcovr, dans le cas de clang ++ en plus llvm-cov gcov pour le convertir. Mais je ne suis pas lié à ces outils, donc si vous avez d'autres outils qui ne montrent pas ce comportement, n'hésitez pas à les suggérer!

Fondamentalement, j'ai besoin d'un moyen de compiler/écrire des tests unitaires pour ce code et obtenir une couverture 100% branche/conditionnelle avec des exceptions activées. Y a-t-il un moyen?

Répondre

1

Eh bien, je crois que votre intention est pas vraiment testé ce petit morceau de code, mais utiliser le concept dans un projet ...

Le code entré déclenche une exception - bad_alloc est levée lorsque vous avez pas de mémoire gauche pour stocker la chaîne qui sera créée avec std::to_string. Pour être sûr à 100%, std::to_string doit être entouré de try-catch, où vous pouvez gérer votre exception.

Pour construire un test d'unité de couverture de code à 100%, vous devez forcer l'exception à se produire - dans ce cas précis, il est presque impossible de garantir, puisque le paramètre est un nombre constant. Mais, dans votre projet, vous avez probablement des données à allouer dont la taille est variable - dans ce cas, vous pouvez isoler dans votre code les méthodes qui allouent de la mémoire, pour les tester séparément. Ensuite, vous passez à ces méthodes, dans la fonction de test, un montant énorme à allouer pour évaluer ce que vous avez mis sur votre bloc catch (et vérifiez si vous le manipulez correctement).

Par exemple, ce code devrait jeter l'exception, vous pouvez l'utiliser pour vous inspirer lors de la construction de vos tests (source):

// bad_alloc.cpp 
// compile with: /EHsc 
#include<new> 
#include<iostream> 
using namespace std; 

int main() { 
    char* ptr; 
    try { 
     ptr = new char[(~unsigned int((int)0)/2) - 1]; 
     delete[] ptr; 
    } 
    catch(bad_alloc &ba) { 
     cout << ba.what() << endl; 
    } 
} 

Toutefois, si vous ne prévoyez pas de traiter toutes les bad_alloc exceptions (ou Absolument toutes les exceptions) dans votre code, il n'y a aucun moyen d'obtenir une couverture de 100% - car il ne sera pas couvert à 100% ... La plupart des cas, une vraie couverture de 100% est inutile, cependant.