3. C++ et le monde extérieur
3.8. Tests
Avant de pouvoir être mis en production les programmes doivent être testés afin d'établir
leur fiabilité et leur tolérance aux fautes.
On recommande aux programmeurs de mettre en place des tests qui ont pour but de débusquer les
bogues inhérants à chaque programme.
En Génie Logiciel notamment une bonne pratique de développement est le Développement Dirigé
par les Tests (Test Driven Development) qui consiste à développer les programmes de tests avant
d'écrire les classes de l'application.
Il existe différents types de tests, on peut citer par exemple :
- les tests unitaires également qualifiés de tests de non-regression qui ont pour but de
tester chaque méthode d'une classe donnée (xUnit)
- les tests d'intégration visent à tester l'interaction entre plusieurs classes
- les tests d'interface cherchent à fiabiliser l'interface graphique ou l'interface web d'une application (Selenium)
- les tests de performance attestent de l'efficacité du traitement des données (JMeter)
- les tests de montée en charge sont utilisés pour les applications web ou l'accès aux bases de
données afin de vérifier qu'un nombre important de connexions ou de requêtes ne risque pas de planter
l'application
Pour réaliser les tests unitaires on peut utiliser :
Le principe de fonctionnement est le suivant : on crée des classes de type TestCase/TestFixture qui sont composées d'un ensemble de méthodes de test. Ces méthodes seront exécutées pour valider les tests et on dispose de macros qui permettent d'assurer la validité du comportement d'un test : CPPUNIT_ASSERT/EXPECT_EQ.
3.8.1. Framework CPPUnit
3.8.1.a installation
Sous Ubuntu 14.04 installer les librairies libcppunit-1.13-0 et libcppunit-dev ou télécharger la dernière version sur freedesktop.org.
3.8.1.b première version
Voici un exemple de base qui introduit des méthodes de test pour la classe vector de la STL :
- il faut définir une classe qui hérite de CppUnit::TestFixture
- définir des méthodes de test
Par défaut, les méthodes suivantes héritées de CppUnit::TestFixture permettent
- setUp d'allouer + initialiser le vecteur à tester rempli avec 100 entiers de 1 à 100
- tearDown de libérer les ressources, ici on supprimer les données dans le vecteur
A l'intérieur de chaque méthode de test on utilise la macro instruction CPPUNIT_ASSERT qui permet de vérifier si une condition est validée ou non.
Il existe d'autres assertions, comme :
- CPPUNIT_ASSERT_EQUAL(expected, actual)
- CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta)
- CPPUNIT_ASSERT_MESSAGE(message, condition)
- CPPUNIT_FAIL(message)
#ifndef TEST_VECTOR_H
#define TEST_VECTOR_H
#include "cppunit/TestCase.h"
#include "cppunit/TestFixture.h"
#include "cppunit/TestCaller.h"
#include "cppunit/TestResult.h"
#include "cppunit/TestSuite.h"
#include "cppunit/CompilerOutputter.h"
#include "cppunit/XmlOutputter.h"
#include "cppunit/ui/text/TestRunner.h"
#include <vector>
using namespace std;
class TestFixture : public CppUnit::TestFixture {
private:
vector<int> v;
public:
// methods inherited from TestFixture
void setUp();
void tearDown();
// test methods
void test_push_back();
void test_erase();
void test_erase_insert();
void test_fail1();
void test_fail2();
};
#endif /* TEST_VECTOR_H */
/*
* test_vector.cpp
*/
#include "test_vector_0.h"
#include <algorithm>
#include <iterator>
#include <numeric>
using namespace std;
// ----------------------------------------------
const int MAX_VALUES = 100;
/**
* setUp: function called before each test
*/
void TestFixture::setUp() {
for (int i=1; i<=MAX_VALUES; ++i) {
v.push_back(i);
}
}
/**
* setUp: function called after each test
*/
void TestFixture::tearDown() {
v.clear();
}
/**
* test that all values are present by computing
* sum i=1,size of v[i] which is supposed to be
* equal to size*(size+1)/2
*/
void TestFixture::test_push_back() {
// vector has been filled by method 'setUp'
int total = accumulate(v.begin(), v.end(), 0);
int expected_total = (MAX_VALUES * (MAX_VALUES+1)) / 2;
CPPUNIT_ASSERT(total == expected_total);
}
/**
* test that the value erased are not present
*/
void TestFixture::test_erase() {
// vector has been filled by method 'setUp'
// remove first and last values
v.erase(v.begin());
v.erase(v.end()-1);
int total = accumulate(v.begin(), v.end(), 0);
int expected_total = (MAX_VALUES * (MAX_VALUES+1)) / 2;
expected_total -= (1 + MAX_VALUES);
CPPUNIT_ASSERT(total == expected_total);
}
/**
* test erase followed by insert of the value
*
* randomly select values, remove them and reinsert them
*
*/
void TestFixture::test_erase_insert() {
// vector has been filled by method 'setUp'
for (int i=0; i<v.size(); ++i) {
int index = rand() % v.size();
int value = v[index];
v.erase(v.begin() + index);
v.insert(v.begin() + rand() % v.size(), value);
}
int total = accumulate(v.begin(), v.end(), 0);
int expected_total = (MAX_VALUES * (MAX_VALUES+1)) / 2;
CPPUNIT_ASSERT(total == expected_total);
}
/**
* Test that will fail, used for example purpose
*/
void TestFixture::test_fail1() {
CPPUNIT_ASSERT(0 == 1);
}
/**
* Test that will fail, used for example purpose
*/
void TestFixture::test_fail2() {
CPPUNIT_ASSERT(true == false);
}
/**
* declare suite of tests
*
*/
CppUnit::TestSuite *make_suite() {
// give a name to the TestSuite
CppUnit::TestSuite *suite = new CppUnit::TestSuite("vector");
cout << "==============================================" << endl;
cout << "TEST " << suite->getName() << " (" << __FILE__ << ")" << endl;
cout << "==============================================" << endl;
// record the methods that needs to be executed
suite->addTest(new CppUnit::TestCaller<TestFixture>("test_push_back",
&TestFixture::test_push_back));
suite->addTest(new CppUnit::TestCaller<TestFixture>("test_erase",
&TestFixture::test_erase));
suite->addTest(new CppUnit::TestCaller<TestFixture>("test_erase_insert",
&TestFixture::test_erase_insert));
suite->addTest(new CppUnit::TestCaller<TestFixture>("test_fail1",
&TestFixture::test_fail1));
suite->addTest(new CppUnit::TestCaller<TestFixture>("test_fail2",
&TestFixture::test_fail2));
return suite;
}
/**
* main function
*/
int main(int argc, char *argv[]) {
CppUnit::TextUi::TestRunner runner;
CppUnit::XmlOutputter *xml_outputter = NULL;
// create suite
CppUnit::TestSuite *suite = make_suite();
runner.addTest(suite);
// set output format as text
runner.setOutputter(new CppUnit::CompilerOutputter(&runner.result(), cout));
// run all tests
runner.run();
// output as XML also
ofstream xml_out("output.xml");
xml_outputter = new CppUnit::XmlOutputter(&runner.result(), xml_out);
xml_outputter->write();
xml_out.close();
return 0;
}
3.8.1.c utilisation simplifiée
Afin de simplifier la déclaration et l'enregistrement des méthodes de tests au niveau du TestSuite, on crée des macro-instructions dans le fichier header :
- TEST_DECL permet de déclarer une méthode de test
- TEST_ADD permet d'ajouter une méthode de test au TestSuite
#ifndef TEST_VECTOR_H
#define TEST_VECTOR_H
#include "cppunit/TestCase.h"
#include "cppunit/TestFixture.h"
#include "cppunit/TestCaller.h"
#include "cppunit/TestResult.h"
#include "cppunit/TestSuite.h"
#include "cppunit/CompilerOutputter.h"
#include "cppunit/XmlOutputter.h"
#include "cppunit/ui/text/TestRunner.h"
#include <vector>
using namespace std;
// Use those macros and repeat the class name three times in
// CLASS_NAME, CLASS_NAME_STRING
#define CLASS_NAME vector
#define CLASS_NAME_STRING "vector"
#define OUTPUT_XML_FILE "output.xml"
#define TEST_DECL(x) void test_##x()
#define TEST_ADD(name) \
suite->addTest(new CppUnit::TestCaller<TestFixture>("test_"#name, \
&TestFixture::test_##name));
class TestFixture : public CppUnit::TestFixture {
private:
vector<int> v;
public:
void setUp();
void tearDown();
TEST_DECL(push_back);
TEST_DECL(erase);
TEST_DECL(erase_insert);
TEST_DECL(fail1);
TEST_DECL(fail2);
};
#endif /* TEST_VECTOR_H */
/*
* test_vector.cpp
*/
#include "test_vector_1.h"
#include <algorithm>
#include <iterator>
#include <numeric>
using namespace std;
// ----------------------------------------------
const int MAX_VALUES = 100;
/**
* setUp: function called before each test
*/
void TestFixture::setUp() {
for (int i=1; i<=MAX_VALUES; ++i) {
v.push_back(i);
}
}
/**
* setUp: function called after each test
*/
void TestFixture::tearDown() {
v.clear();
}
/**
* test that all values are present by computing
* sum i=1,size of v[i] which is supposed to be
* equal to size*(size+1)/2
*/
void TestFixture::test_push_back() {
// vector has been filled by method 'setUp'
int total = accumulate(v.begin(), v.end(), 0);
int expected_total = (MAX_VALUES * (MAX_VALUES+1)) / 2;
CPPUNIT_ASSERT(total == expected_total);
}
/**
* test that the value erased are not present
*/
void TestFixture::test_erase() {
// vector has been filled by method 'setUp'
// remove first and last values
v.erase(v.begin());
v.erase(v.end()-1);
int total = accumulate(v.begin(), v.end(), 0);
int expected_total = (MAX_VALUES * (MAX_VALUES+1)) / 2;
expected_total -= (1 + MAX_VALUES);
CPPUNIT_ASSERT(total == expected_total);
}
/**
* test erase followed by insert of the value
*
* randomly select values, remove them and reinsert them
*
*/
void TestFixture::test_erase_insert() {
// vector has been filled by method 'setUp'
for (int i=0; i<v.size(); ++i) {
int index = rand() % v.size();
int value = v[index];
v.erase(v.begin() + index);
v.insert(v.begin() + rand() % v.size(), value);
}
int total = accumulate(v.begin(), v.end(), 0);
int expected_total = (MAX_VALUES * (MAX_VALUES+1)) / 2;
CPPUNIT_ASSERT(total == expected_total);
}
/**
* Test that will fail, used for example purpose
*/
void TestFixture::test_fail1() {
CPPUNIT_ASSERT(0 == 1);
}
/**
* Test that will fail, used for example purpose
*/
void TestFixture::test_fail2() {
CPPUNIT_ASSERT(true == false);
}
/**
* declare suite of tests
*
*/
CppUnit::TestSuite *make_suite() {
CppUnit::TestSuite *suite = new CppUnit::TestSuite(CLASS_NAME_STRING);
cout << "==============================================" << endl;
cout << "TEST " << suite->getName() << " (" << __FILE__ << ")" << endl;
cout << "==============================================" << endl;
TEST_ADD(push_back);
TEST_ADD(erase);
TEST_ADD(erase_insert);
TEST_ADD(fail1);
TEST_ADD(fail2);
return suite;
}
/**
* main function
*/
int main(int argc, char *argv[]) {
CppUnit::TextUi::TestRunner runner;
CppUnit::XmlOutputter *xml_outputter = NULL;
// create suite
CppUnit::TestSuite *suite = make_suite();
runner.addTest(suite);
// set output format as text
runner.setOutputter(new CppUnit::CompilerOutputter(&runner.result(), cout));
// run all tests
runner.run();
// output as XML also
ofstream xml_out(OUTPUT_XML_FILE);
xml_outputter = new CppUnit::XmlOutputter(&runner.result(), xml_out);
xml_outputter->write();
xml_out.close();
return 0;
}
3.8.1.d compilation, exécution
On compile avec les options suivantes :
g++ -o test_vector_1.exe test_vector_1.cpp -lcppunit
Puis on exécute en lançant le programme, voici le résultat de la sortie en mode texte :
./test_vector_1.exe
==============================================
TEST vector (test_vector_1.cpp)
==============================================
....F.F
test_vector_1.cpp:89:Assertion
Test name: test_fail1
assertion failed
- Expression: 0 == 1
test_vector_1.cpp:96:Assertion
Test name: test_fail2
assertion failed
- Expression: true == false
Failures !!!
Run: 5 Failure total: 2 Failures: 2 Errors: 0
Le programme reporte les assertions non vérifiées :
- CPPUNIT_ASSERT(0 == 1); de la ligne 89 du programme test_vector_1.cpp
- et CPPUNIT_ASSERT(true == false); de la ligne 96.
Voici la sortie au format XML :
- les tests qui ont échoué sont dans la section FailedTests (ligne 3)
- le nombre de tests exécutés figure en ligne 38 dans la section Statistics
<?xml version="1.0" encoding='ISO-8859-1' standalone='yes' ?>
<TestRun>
<FailedTests>
<FailedTest id="4">
<Name>test_fail1</Name>
<FailureType>Assertion</FailureType>
<Location>
<File>test_vector_0.cpp</File>
<Line>89</Line>
</Location>
<Message>assertion failed
- Expression: 0 == 1
</Message>
</FailedTest>
<FailedTest id="5">
<Name>test_fail2</Name>
<FailureType>Assertion</FailureType>
<Location>
<File>test_vector_0.cpp</File>
<Line>96</Line>
</Location>
<Message>assertion failed
- Expression: true == false
</Message>
</FailedTest>
</FailedTests>
<SuccessfulTests>
<Test id="1">
<Name>test_push_back</Name>
</Test>
<Test id="2">
<Name>test_erase</Name>
</Test>
<Test id="3">
<Name>test_erase_insert</Name>
</Test>
</SuccessfulTests>
<Statistics>
<Tests>5</Tests>
<FailuresTotal>2</FailuresTotal>
<Errors>0</Errors>
<Failures>2</Failures>
</Statistics>
</TestRun>
On peut ensuite extraire les méthodes qui ont échoué grâce à un utilitaire comme xpath du package libxml-xpath-perl :
sudo apt-get install libxml-xpath-perl
> xpath -q -e "//FailedTest/Name/text()" output.xml
test_fail1
test_fail2
Voici un script shell qui permet de récupérer les noms des méthodes qui ont échoué tout en
vérifiant que tous les tests ont été exécutés :
#!/bin/sh
files=`ls test_*_1.exe`
for f in $files ; do
./$f >tmp.txt
x=`xpath -q -e "//FailedTest/Name/text()" output.xml`
echo "===================";
echo "$f"
echo "$x" | awk '{ print "-", $1; }'
echo "===================";
done
> ./cppunit_failures_1.sh
===================
test_vector_1.exe
- test_fail1
- test_fail2
===================
3.8.1.e version avancée
Voici une version avancée qui prend en compte le nombre de tests et qui permet de vérifier
que l'ensemble des tests à été exécuté.
En effet, si l'une methode échoue et provoque par exemple un segmentation fault, les autres méthodes
ne seront pas exécutées et il ne sera pas possible de le savoir. On risque donc de penser que tout va bien alors
que certains tests n'ont pas été exécutés.
#ifndef TEST_VECTOR_H
#define TEST_VECTOR_H
#include "cppunit/TestCase.h"
#include "cppunit/TestFixture.h"
#include "cppunit/TestCaller.h"
#include "cppunit/TestResult.h"
#include "cppunit/TestSuite.h"
#include "cppunit/CompilerOutputter.h"
#include "cppunit/XmlOutputter.h"
#include "cppunit/ui/text/TestRunner.h"
#include <vector>
using namespace std;
// Use those macros and repeat the class name three times in
// CLASS_NAME, CLASS_NAME_STRING, OUTPUT_XML_FILE
#define CLASS_NAME vector
#define CLASS_NAME_STRING "vector"
#define OUTPUT_XML_FILE "test_vector.xml"
#define TEST_DECL(x) void test_##x()
#define ADD_TEST(name) \
suite->addTest(new CppUnit::TestCaller<TestFixture>("test_"#name, \
&TestFixture::test_##name));
class TestFixture : public CppUnit::TestFixture {
private:
vector<int> v;
public:
void setUp();
void tearDown();
TEST_DECL(push_back);
TEST_DECL(erase);
TEST_DECL(erase_insert);
TEST_DECL(fail1);
TEST_DECL(fail2);
TEST_DECL(div_by_zero);
};
#endif /* TEST_VECTOR_H */
/*
* test_vector_2.cpp
*/
#include "test_vector_2.h"
#include <algorithm>
#include <iterator>
#include <numeric>
using namespace std;
#include <getopt.h>
#include <cstring>
#include <signal.h>
#include <err.h>
#include <cstdlib>
#include <cstdio>
void signal_handler(int sig) {
cerr << endl << "caught signal " << sig << endl;
cerr.flush();
return ;
}
void set_signal_handler() {
signal( SIGABRT, signal_handler);
signal( SIGHUP, signal_handler);
signal( SIGILL, signal_handler);
}
// ----------------------------------------------
// description of possible arguments
// that can be used in
// - short format : -m 1
// - or long format : --method=1
// ----------------------------------------------
static struct option long_options[] = {
{"nbr-tests", no_argument, 0, 'n'},
{"output-format", required_argument, 0, 'f'},
{0,0,0,0}
};
typedef struct {
string output_file;
int output_format;
bool flag_get_nbr_tests;
} Parameters;
Parameters params;
const char *params_format_allowed[] = { "text", "xml", NULL };
int get_allowed_value(const char *s, const char *tab[]) {
for (int i=0; tab[i] != NULL; ++i) {
if (strcmp(s,tab[i])==0) return i;
}
return -1;
}
void usage(char *prog_name) {
cout << prog_name << endl;
cout << "--output-format=text|xml" << endl;
cout << "--nbr-tests" << endl;
exit(EXIT_FAILURE);
}
// ----------------------------------------------
const int MAX_VALUES = 100;
/**
* setUp: function called before each test
*/
void TestFixture::setUp() {
for (int i=1; i<=MAX_VALUES; ++i) {
v.push_back(i);
}
}
/**
* setUp: function called after each test
*/
void TestFixture::tearDown() {
v.clear();
}
/**
* test that all values are present by computing
* sum i=1,size of v[i] which is supposed to be
* equal to size*(size+1)/2
*/
void TestFixture::test_push_back() {
// vector has been filled by method 'setUp'
int total = accumulate(v.begin(), v.end(), 0);
int expected_total = (MAX_VALUES * (MAX_VALUES+1)) / 2;
CPPUNIT_ASSERT(total == expected_total);
}
/**
* test that the value erased are not present
*/
void TestFixture::test_erase() {
// vector has been filled by method 'setUp'
// remove first and last values
v.erase(v.begin());
v.erase(v.end()-1);
int total = accumulate(v.begin(), v.end(), 0);
int expected_total = (MAX_VALUES * (MAX_VALUES+1)) / 2;
expected_total -= (1 + MAX_VALUES);
CPPUNIT_ASSERT(total == expected_total);
}
/**
* test erase followed by insert of the value
*
* randomly select values, remove them and reinsert them
*
*/
void TestFixture::test_erase_insert() {
// vector has been filled by method 'setUp'
for (int i=0; i<v.size(); ++i) {
int index = rand() % v.size();
int value = v[index];
v.erase(v.begin() + index);
v.insert(v.begin() + rand() % v.size(), value);
}
int total = accumulate(v.begin(), v.end(), 0);
int expected_total = (MAX_VALUES * (MAX_VALUES+1)) / 2;
CPPUNIT_ASSERT(total == expected_total);
}
/**
* Test that will fail, used for example purpose
*/
void TestFixture::test_fail1() {
CPPUNIT_ASSERT(0 == 1);
}
/**
* Test that will fail, used for example purpose
*/
void TestFixture::test_fail2() {
CPPUNIT_ASSERT(true == false);
}
/**
* Test that will fail with a division by zero,
* used for example purpose
*/
void TestFixture::test_div_by_zero() {
int a = 0;
int b = 10;
int c = b / a;
CPPUNIT_ASSERT(c != 0);
}
/**
* declare suite of tests
*
*/
CppUnit::TestSuite *make_suite() {
CppUnit::TestSuite *suite = new CppUnit::TestSuite(CLASS_NAME_STRING);
cout << "==============================================" << endl;
cout << "TEST " << suite->getName() << " (" << __FILE__ << ")" << endl;
cout << "==============================================" << endl;
ADD_TEST(push_back);
ADD_TEST(erase);
ADD_TEST(erase_insert);
ADD_TEST(fail1);
ADD_TEST(fail2);
ADD_TEST(div_by_zero);
return suite;
}
/**
* main function
*/
int main(int argc, char *argv[]) {
CppUnit::TextUi::TestRunner runner;
CppUnit::XmlOutputter *xml_outputter = NULL;
params.output_file = "";
params.output_format = 0; // text
params.flag_get_nbr_tests = false;
int option_index;
while (true) {
option_index = 0;
int c = getopt_long(argc, argv, "f:n", long_options, &option_index);
if (c == -1) break;
switch(c) {
case 'n':
params.flag_get_nbr_tests = true;
break;
case 'f':
params.output_format = get_allowed_value(optarg, params_format_allowed);
break;
}
}
if (params.output_format == -1) {
usage(argv[0]);
}
set_signal_handler();
// create suite
CppUnit::TestSuite *suite = make_suite();
runner.addTest(suite);
if (params.output_format == 1) {
cout << "xml file=" << OUTPUT_XML_FILE << endl;
}
if (params.flag_get_nbr_tests == true) {
const std::vector<CppUnit::Test *>& tests = suite->getTests();
cout << "nbr_tests=" << tests.size() << endl;
exit(EXIT_SUCCESS);
}
// set output format as text
runner.setOutputter(new CppUnit::CompilerOutputter(&runner.result(), cout));
// run all tests
runner.run();
if (params.output_format == 1) {
ofstream xml_out(OUTPUT_XML_FILE);
xml_outputter = new CppUnit::XmlOutputter(&runner.result(), xml_out);
xml_outputter->write();
xml_out.close();
}
return 0;
}
#!/bin/sh
execute_test()
{
./$f --output-format=xml >tmp2.txt
}
files=`ls test*_2.exe`
for f in $files ; do
./$f --nbr-test --output-format=xml >tmp.txt
nbr=`cat tmp.txt | grep "^nbr_tests=" | cut -d'=' -f2`
# SIGHUP SIGQUIT SIGINT SIGABRT
echo "execute $f "
trap execute_test 1 2 3 6
xml=`cat tmp.txt | grep "^xml file=" | cut -d'=' -f2`
r=""
if test -f $xml ; then
x=`xpath -q -e "//FailedTest/Name/text()" $xml`
r=`xpath -q -e "//Statistics//Tests/text()" $xml`
echo "===================";
if test -n "$x" ; then
echo "$f"
echo "$x" | awk '{ print "-", $1; }'
fi
if test $nbr != $r ; then
echo "failed ! $nbr tests expected, only $r performed"
fi
echo "===================";
else
echo "===================";
echo "$f FAILURE ! Program did not terminate"
echo "===================";
fi
done
> ./cppunit_failures_1.sh
===================
test_vector_1.exe
- test_fail1
- test_fail2
===================
3.8.2. Framework Google Test
Récupérer googletest-release-1.7.0.tar.gz sur googletest, puis dans le répertoire où le fichier a été télécharger. Il n'y a pas (en tout cas dans la version 1.7) de méthode d'installation automatisée. Il faut donc saisir dans le terminal les commandes suivantes :
sudo tar -xvzf googletest-release-1.7.0.tar.gz -C /opt
sudo su
cd /opt/googletest-release-1.7.0
cmake -DBUILD_SHARED_LIBS=ON -Dgtest_build_samples=ON -G "Unix Makefiles"
make
cp -R include/gtest /usr/include
cp lib*.a /usr/lib
ldconfig
exit
Pour tester, créer le fichier suivant :
#include <gtest/gtest.h>
TEST(MathTest, TwoPlusTwoEqualsFour) {
EXPECT_EQ(2 + 2, 4);
}
TEST(MathTest, ThatWillFail) {
EXPECT_EQ(0, 1);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest( &argc, argv );
return RUN_ALL_TESTS();
}
et compiler avec :
g++ -o my_gtest.exe my_gtest.cpp -lgtest -lgtest_main -lpthread
./my_gtest.exe
[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from MathTest
[ RUN ] MathTest.TwoPlusTwoEqualsFour
[ OK ] MathTest.TwoPlusTwoEqualsFour (0 ms)
[ RUN ] MathTest.ThatWillFail
my_gtest.cpp:8: Failure
Value of: 1
Expected: 0
[ FAILED ] MathTest.ThatWillFail (0 ms)
[----------] 2 tests from MathTest (0 ms total)
[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran. (0 ms total)
[ PASSED ] 1 test.
[ FAILED ] 1 test, listed below:
[ FAILED ] MathTest.ThatWillFail
avec XML
./my_gtest.exe --gtest_output="xml:report.xml"
...
<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="2" failures="1" disabled="0" errors="0" timestamp="2015-11-25T11:14:56" time="0.001" name="AllTests">
<testsuite name="MathTest" tests="2" failures="1" disabled="0" errors="0" time="0.001">
<testcase name="TwoPlusTwoEqualsFour" status="run" time="0" classname="MathTest" />
<testcase name="ThatWillFail" status="run" time="0.001" classname="MathTest">
<failure message="my_gtest.cpp:8
Value of: 1
Expected: 0" type=""><![CDATA[my_gtest.cpp:8
Value of: 1
Expected: 0]]></failure>
</testcase>
</testsuite>
</testsuites>
La définition des tests est réalisée grâce à la macro-instruction TEST(NomTestCase, NomMethodeDeTest).