Aan de slag met CppUTest

Bird

14 mei 2017

E-mail

1 min read

Aan de slag met CppUTest

Belangrijkste punten

    • CppUTest is een lichte, actief onderhouden xUnit-stijl testframework voor C/C++, met een C integratielaag die naadloos werkt, zelfs in C-zware codebases.

    • Je kunt het installeren via pakketmanagers (Linux distributies, Homebrew) of de GitHub repo klonen.

    • Een minimale installatie bestaat uit:

      • een productie src/ directory,

      • een t/ test directory,

      • een test runner (CommandLineTestRunner), en

      • testmodules met behulp van TEST_GROUP en TEST() blokken.

    • CppUTest levert een MakefileWorker.mk helper die het bouwen van tests, het koppelen van bibliotheken en het omgaan met vlaggen vereenvoudigt.

    • Detectie van geheugenlekken is standaard ingeschakeld via malloc/free overrides, waardoor lekken binnen de geteste broncode worden gevangen.

    • Code dekking via gcov integreert eenvoudig door CPPUTEST_USE_GCOV=Y in te schakelen, wat volledige dekking rapporten en HTML samenvattingen produceert.

    • Het framework bevat geavanceerde functies: mocken, plugins, helper scripts en directe C-interoperabiliteit — nuttig voor complexe zakelijke codebases.

Q&A Hoogtepunten

  • Wat is CppUTest en waarom zou je het gebruiken?

    Het is een robuust, xUnit-stijl testframework voor C/C++ met een schone API, ingebouwde assert-macro's, lekkagedetectie en actieve ontwikkeling — ideaal voor legacy- of moderne systemen.

  • Hoe structureer je een basisproject met CppUTest?

    src/
      code/
        code.cpp
        code.h
      main.cpp
    t/
      main.cpp (test runner)
      test.cpp (test suite)
  • Hoe voert u alle tests uit?

    De testrunner gebruikt:

    return CommandLineTestRunner::RunAllTests(ac, av);
  • Hoe bouw je tests zonder handmatig compileropties te configureren?

    Gebruik MakefileWorker.mk van CppUTest, dat de flags, het linken en de uitvoering van tests automatisch afhandelt.

  • Kan CppUTest automatisch geheugenlekken detecteren?

    Ja. Het overschrijft malloc/free tijdens testbuilds en rapporteert:

    • welke test lekte,

    • waar het plaatsvond,

    • lekgrootte en geheugeninhoud.

    Voorbeeld van foutweergave:

    Memory leak(s) found.
    Allocated at: code.c line 6
    Leak size: 1
  • Hoe genereer ik code coverage?

    1. Inschakelen: CPPUTEST_USE_GCOV=Y

    2. Zorg ervoor dat filterGcov.sh beschikbaar is op $(CPPUTEST_HOME)/scripts/.

    3. Uitvoeren: maak gcov

      Dit produceert .gcov, samenvattende tekst en HTML-dekkingsrapporten.

  • Wat kan CppUTest nog meer doen naast basis testen?

    • mocking framework

    • plugin systeem

    • automatiseringsscripts voor helpers

    • native C-integratie

    • uitgebreide assertiemacros

  • Voor wie is CppUTest het meest geschikt?

    Teams die werken met embedded systems, C-platforms, C++-diensten, of elke omgeving waar betrouwbaarheid en geheugensicherheit continu moeten worden gevalideerd.

Bij SparkPost steken we veel tijd en moeite in het testen van onze code. Ons platform is geschreven in C en recentelijk heb ik onderzoek gedaan naar de integratie met een unit testing framework genaamd “CppUTest”, dat xUnit-stijl testen biedt voor C/C++. Dit framework is robuust, rijk aan functies en in actieve ontwikkeling, wat het een geweldige keuze maakt. Het biedt ook een C-integratielaag, waardoor het gemakkelijk te gebruiken is met onze platform C-code, zelfs als het grootste deel van het framework in C++ is. Deze tutorial behandelt hoe u kunt beginnen met CppUTest voor uw eigen projecten.

Bij SparkPost steken we veel tijd en moeite in het testen van onze code. Ons platform is geschreven in C en recentelijk heb ik onderzoek gedaan naar de integratie met een unit testing framework genaamd “CppUTest”, dat xUnit-stijl testen biedt voor C/C++. Dit framework is robuust, rijk aan functies en in actieve ontwikkeling, wat het een geweldige keuze maakt. Het biedt ook een C-integratielaag, waardoor het gemakkelijk te gebruiken is met onze platform C-code, zelfs als het grootste deel van het framework in C++ is. Deze tutorial behandelt hoe u kunt beginnen met CppUTest voor uw eigen projecten.

Bij SparkPost steken we veel tijd en moeite in het testen van onze code. Ons platform is geschreven in C en recentelijk heb ik onderzoek gedaan naar de integratie met een unit testing framework genaamd “CppUTest”, dat xUnit-stijl testen biedt voor C/C++. Dit framework is robuust, rijk aan functies en in actieve ontwikkeling, wat het een geweldige keuze maakt. Het biedt ook een C-integratielaag, waardoor het gemakkelijk te gebruiken is met onze platform C-code, zelfs als het grootste deel van het framework in C++ is. Deze tutorial behandelt hoe u kunt beginnen met CppUTest voor uw eigen projecten.

CppUTest downloaden

De CppUTest-projectpagina is beschikbaar op de officiële website, en de repository is te vinden op github. Het is ook opgenomen in de pakketbeheer repositories voor veel linux distro's, evenals homebrew op Mac OS. De volgende voorbeelden zijn uitgevoerd op Mac OS X, maar ze zijn afgeleid van code geschreven voor Red Hat, het besturingssysteem waarop ons platform draait.

De basisprincipes zijn goed gedocumenteerd op de startpagina van CppUTest. We gaan daar snel doorheen en komen bij enkele van de interessantere functies.

De CppUTest-projectpagina is beschikbaar op de officiële website, en de repository is te vinden op github. Het is ook opgenomen in de pakketbeheer repositories voor veel linux distro's, evenals homebrew op Mac OS. De volgende voorbeelden zijn uitgevoerd op Mac OS X, maar ze zijn afgeleid van code geschreven voor Red Hat, het besturingssysteem waarop ons platform draait.

De basisprincipes zijn goed gedocumenteerd op de startpagina van CppUTest. We gaan daar snel doorheen en komen bij enkele van de interessantere functies.

De CppUTest-projectpagina is beschikbaar op de officiële website, en de repository is te vinden op github. Het is ook opgenomen in de pakketbeheer repositories voor veel linux distro's, evenals homebrew op Mac OS. De volgende voorbeelden zijn uitgevoerd op Mac OS X, maar ze zijn afgeleid van code geschreven voor Red Hat, het besturingssysteem waarop ons platform draait.

De basisprincipes zijn goed gedocumenteerd op de startpagina van CppUTest. We gaan daar snel doorheen en komen bij enkele van de interessantere functies.

Het Fundament Leggen

Eerst en vooral, laten we wat code schrijven!

Ons testproject zal een ‘main’ bestand hebben en bevat een hulplibrary genaamd ‘code’. De library zal een eenvoudige functie bieden die 1 retourneert (voor nu). De bestanden worden als volgt ingedeeld:

├── src
├── code
├── code.cpp
└── code.h
└── main.cpp
└── t
    ├── main.cpp
    └── test.cpp

Laten we beginnen met het schrijven van de src/ bestanden

// src/main.cpp
#include <stdlib.h>
#include <stdio.h>
#include "code.h"
int main(void) {
    test_func();
    printf("hello world!\n");
    exit(0);
}


// src/code/code.cpp
#include <stdlib.h>
#include "code.h"
int test_func() {
    return 1;
}


// src/code/code.h
#ifndef __code_h__
#define __code_h__
int test_func();
#endif

Nu, laten we de tests doen, die in de t/ directory zullen staan.  Het eerste wat we moeten doen is een testrunner instellen die onze testbestanden zal uitvoeren. Dit is ook de ‘main’ functie die zal worden uitgevoerd zodra dit alles is gecompileerd:

// t/main.cpp
#include "CppUTest/CommandLineTestRunner.h"
int main(int ac, char** av) {
return CommandLineTestRunner::RunAllTests(ac, av);
}

Nu kunnen we onze eerste testmodule schrijven:

// t/test.cpp
#include "CppUTest/TestHarness.h"
#include "code.h"
TEST_GROUP(AwesomeExamples)
{
};
TEST(AwesomeExamples, FirstExample)
{
    int x = test_func();
    CHECK_EQUAL(1, x);
}

Vervolgens moeten we makefiles schrijven.  We hebben er twee nodig: één voor de projectbestanden onder src/, en één voor de tests.

Eerst en vooral, laten we wat code schrijven!

Ons testproject zal een ‘main’ bestand hebben en bevat een hulplibrary genaamd ‘code’. De library zal een eenvoudige functie bieden die 1 retourneert (voor nu). De bestanden worden als volgt ingedeeld:

├── src
├── code
├── code.cpp
└── code.h
└── main.cpp
└── t
    ├── main.cpp
    └── test.cpp

Laten we beginnen met het schrijven van de src/ bestanden

// src/main.cpp
#include <stdlib.h>
#include <stdio.h>
#include "code.h"
int main(void) {
    test_func();
    printf("hello world!\n");
    exit(0);
}


// src/code/code.cpp
#include <stdlib.h>
#include "code.h"
int test_func() {
    return 1;
}


// src/code/code.h
#ifndef __code_h__
#define __code_h__
int test_func();
#endif

Nu, laten we de tests doen, die in de t/ directory zullen staan.  Het eerste wat we moeten doen is een testrunner instellen die onze testbestanden zal uitvoeren. Dit is ook de ‘main’ functie die zal worden uitgevoerd zodra dit alles is gecompileerd:

// t/main.cpp
#include "CppUTest/CommandLineTestRunner.h"
int main(int ac, char** av) {
return CommandLineTestRunner::RunAllTests(ac, av);
}

Nu kunnen we onze eerste testmodule schrijven:

// t/test.cpp
#include "CppUTest/TestHarness.h"
#include "code.h"
TEST_GROUP(AwesomeExamples)
{
};
TEST(AwesomeExamples, FirstExample)
{
    int x = test_func();
    CHECK_EQUAL(1, x);
}

Vervolgens moeten we makefiles schrijven.  We hebben er twee nodig: één voor de projectbestanden onder src/, en één voor de tests.

Eerst en vooral, laten we wat code schrijven!

Ons testproject zal een ‘main’ bestand hebben en bevat een hulplibrary genaamd ‘code’. De library zal een eenvoudige functie bieden die 1 retourneert (voor nu). De bestanden worden als volgt ingedeeld:

├── src
├── code
├── code.cpp
└── code.h
└── main.cpp
└── t
    ├── main.cpp
    └── test.cpp

Laten we beginnen met het schrijven van de src/ bestanden

// src/main.cpp
#include <stdlib.h>
#include <stdio.h>
#include "code.h"
int main(void) {
    test_func();
    printf("hello world!\n");
    exit(0);
}


// src/code/code.cpp
#include <stdlib.h>
#include "code.h"
int test_func() {
    return 1;
}


// src/code/code.h
#ifndef __code_h__
#define __code_h__
int test_func();
#endif

Nu, laten we de tests doen, die in de t/ directory zullen staan.  Het eerste wat we moeten doen is een testrunner instellen die onze testbestanden zal uitvoeren. Dit is ook de ‘main’ functie die zal worden uitgevoerd zodra dit alles is gecompileerd:

// t/main.cpp
#include "CppUTest/CommandLineTestRunner.h"
int main(int ac, char** av) {
return CommandLineTestRunner::RunAllTests(ac, av);
}

Nu kunnen we onze eerste testmodule schrijven:

// t/test.cpp
#include "CppUTest/TestHarness.h"
#include "code.h"
TEST_GROUP(AwesomeExamples)
{
};
TEST(AwesomeExamples, FirstExample)
{
    int x = test_func();
    CHECK_EQUAL(1, x);
}

Vervolgens moeten we makefiles schrijven.  We hebben er twee nodig: één voor de projectbestanden onder src/, en één voor de tests.

Project Makefile

Het project makefile zal zich op hetzelfde niveau bevinden als de ‘src’ en ‘t’ directories aan de basis van het project. Het zou er zo uit moeten zien:

# Makefile

SRC_DIR = ./src
CODE_DIR = $(SRC_DIR)/code
OUT = example
TEST_DIR = t

test:
make -C $(TEST_DIR)

test_clean:
make -C $(TEST_DIR) clean

code.o:
gcc -c -I$(CODE_DIR) $(CODE_DIR)/code.cpp -o $(CODE_DIR)/code.o

main: code.o
gcc -I$(CODE_DIR) $(CODE_DIR)/code.o $(SRC_DIR)/main.cpp -o $(OUT)

all: test main

clean: test_clean
rm $(SRC_DIR)/*.o $(CODE_DIR)/*.o $(OUT)

Let op dat dit ‘make -C’ gebruikt voor de testdoelen – wat betekent dat het ‘make’ opnieuw zal aanroepen met gebruik van de makefile in de testdirectory.

Op dit punt kunnen wij de ‘src’ code compileren met de makefile en zien dat het werkt:

[]$ make main
gcc -c -I./src/code ./src/code/code.cpp -o ./src/code/code.o
gcc -I./src/code ./src/code/code.o ./src/main.cpp -o example
[]$ ./example
hello world

Het project makefile zal zich op hetzelfde niveau bevinden als de ‘src’ en ‘t’ directories aan de basis van het project. Het zou er zo uit moeten zien:

# Makefile

SRC_DIR = ./src
CODE_DIR = $(SRC_DIR)/code
OUT = example
TEST_DIR = t

test:
make -C $(TEST_DIR)

test_clean:
make -C $(TEST_DIR) clean

code.o:
gcc -c -I$(CODE_DIR) $(CODE_DIR)/code.cpp -o $(CODE_DIR)/code.o

main: code.o
gcc -I$(CODE_DIR) $(CODE_DIR)/code.o $(SRC_DIR)/main.cpp -o $(OUT)

all: test main

clean: test_clean
rm $(SRC_DIR)/*.o $(CODE_DIR)/*.o $(OUT)

Let op dat dit ‘make -C’ gebruikt voor de testdoelen – wat betekent dat het ‘make’ opnieuw zal aanroepen met gebruik van de makefile in de testdirectory.

Op dit punt kunnen wij de ‘src’ code compileren met de makefile en zien dat het werkt:

[]$ make main
gcc -c -I./src/code ./src/code/code.cpp -o ./src/code/code.o
gcc -I./src/code ./src/code/code.o ./src/main.cpp -o example
[]$ ./example
hello world

Het project makefile zal zich op hetzelfde niveau bevinden als de ‘src’ en ‘t’ directories aan de basis van het project. Het zou er zo uit moeten zien:

# Makefile

SRC_DIR = ./src
CODE_DIR = $(SRC_DIR)/code
OUT = example
TEST_DIR = t

test:
make -C $(TEST_DIR)

test_clean:
make -C $(TEST_DIR) clean

code.o:
gcc -c -I$(CODE_DIR) $(CODE_DIR)/code.cpp -o $(CODE_DIR)/code.o

main: code.o
gcc -I$(CODE_DIR) $(CODE_DIR)/code.o $(SRC_DIR)/main.cpp -o $(OUT)

all: test main

clean: test_clean
rm $(SRC_DIR)/*.o $(CODE_DIR)/*.o $(OUT)

Let op dat dit ‘make -C’ gebruikt voor de testdoelen – wat betekent dat het ‘make’ opnieuw zal aanroepen met gebruik van de makefile in de testdirectory.

Op dit punt kunnen wij de ‘src’ code compileren met de makefile en zien dat het werkt:

[]$ make main
gcc -c -I./src/code ./src/code/code.cpp -o ./src/code/code.o
gcc -I./src/code ./src/code/code.o ./src/main.cpp -o example
[]$ ./example
hello world

Tests Makefile

Voor de tests zijn de zaken iets ingewikkelder, aangezien we de CppUTest-bibliotheek correct moeten laden en integreren.

De CppUTest-repository biedt een bestand genaamd 'MakefileWorker.mk'. Het biedt veel functionaliteit die het bouwen met CppUTest eenvoudig maakt. Het bestand bevindt zich in de map 'build' in de git-repository. Voor deze tutorial gaan we ervan uit dat het naar de 't/'-map is gekopieerd. Het kan als volgt worden gebruikt:

# we don’t want to use relative paths, so we set these variables
PROJECT_DIR=/path/to/project
SRC_DIR=$(PROJECT_DIR)/src
TEST_DIR=$(PROJECT_DIR)/t

# specify where the source code and includes are located
INCLUDE_DIRS=$(SRC_DIR)/code
SRC_DIRS=$(SRC_DIR)/code

# specify where the test code is located
TEST_SRC_DIRS=$(TEST_DIR)

# what to call the test binary
TEST_TARGET=example

# where the cpputest library is located
CPPUTEST_HOME=/usr/local

# run MakefileWorker.mk with the variables defined here
include MakefileWorker.mk

Merk op dat CPPUTEST_HOME moet worden ingesteld op de locatie waar CppUTest is geïnstalleerd. Als u een distributiepakket hebt geïnstalleerd, bevindt dit zich meestal onder /usr/local op een linux/mac-systeem. Als u de repository zelf hebt uitgecheckt, is het waar die checkout is gedaan.

Deze opties zijn allemaal gedocumenteerd in MakefileWorker.mk.

MakefileWorker.mk voegt ook een paar makefile-doelstellingen toe, waaronder de volgende:

  1. all – bouwt de tests die door het makefile worden aangegeven

  2. clean – verwijdert alle gegenereerde object- en gcov-bestanden voor de tests

  3. realclean – verwijdert alle object- of gcov-bestanden in de gehele directorystructuur

  4. flags – geeft alle geconfigureerde flags weer die worden gebruikt om de tests te compileren

  5. debug – geeft alle bronbestanden, objecten, afhankelijkheden en 'schoon te maken onderdelen' weer

Voor de tests zijn de zaken iets ingewikkelder, aangezien we de CppUTest-bibliotheek correct moeten laden en integreren.

De CppUTest-repository biedt een bestand genaamd 'MakefileWorker.mk'. Het biedt veel functionaliteit die het bouwen met CppUTest eenvoudig maakt. Het bestand bevindt zich in de map 'build' in de git-repository. Voor deze tutorial gaan we ervan uit dat het naar de 't/'-map is gekopieerd. Het kan als volgt worden gebruikt:

# we don’t want to use relative paths, so we set these variables
PROJECT_DIR=/path/to/project
SRC_DIR=$(PROJECT_DIR)/src
TEST_DIR=$(PROJECT_DIR)/t

# specify where the source code and includes are located
INCLUDE_DIRS=$(SRC_DIR)/code
SRC_DIRS=$(SRC_DIR)/code

# specify where the test code is located
TEST_SRC_DIRS=$(TEST_DIR)

# what to call the test binary
TEST_TARGET=example

# where the cpputest library is located
CPPUTEST_HOME=/usr/local

# run MakefileWorker.mk with the variables defined here
include MakefileWorker.mk

Merk op dat CPPUTEST_HOME moet worden ingesteld op de locatie waar CppUTest is geïnstalleerd. Als u een distributiepakket hebt geïnstalleerd, bevindt dit zich meestal onder /usr/local op een linux/mac-systeem. Als u de repository zelf hebt uitgecheckt, is het waar die checkout is gedaan.

Deze opties zijn allemaal gedocumenteerd in MakefileWorker.mk.

MakefileWorker.mk voegt ook een paar makefile-doelstellingen toe, waaronder de volgende:

  1. all – bouwt de tests die door het makefile worden aangegeven

  2. clean – verwijdert alle gegenereerde object- en gcov-bestanden voor de tests

  3. realclean – verwijdert alle object- of gcov-bestanden in de gehele directorystructuur

  4. flags – geeft alle geconfigureerde flags weer die worden gebruikt om de tests te compileren

  5. debug – geeft alle bronbestanden, objecten, afhankelijkheden en 'schoon te maken onderdelen' weer

Voor de tests zijn de zaken iets ingewikkelder, aangezien we de CppUTest-bibliotheek correct moeten laden en integreren.

De CppUTest-repository biedt een bestand genaamd 'MakefileWorker.mk'. Het biedt veel functionaliteit die het bouwen met CppUTest eenvoudig maakt. Het bestand bevindt zich in de map 'build' in de git-repository. Voor deze tutorial gaan we ervan uit dat het naar de 't/'-map is gekopieerd. Het kan als volgt worden gebruikt:

# we don’t want to use relative paths, so we set these variables
PROJECT_DIR=/path/to/project
SRC_DIR=$(PROJECT_DIR)/src
TEST_DIR=$(PROJECT_DIR)/t

# specify where the source code and includes are located
INCLUDE_DIRS=$(SRC_DIR)/code
SRC_DIRS=$(SRC_DIR)/code

# specify where the test code is located
TEST_SRC_DIRS=$(TEST_DIR)

# what to call the test binary
TEST_TARGET=example

# where the cpputest library is located
CPPUTEST_HOME=/usr/local

# run MakefileWorker.mk with the variables defined here
include MakefileWorker.mk

Merk op dat CPPUTEST_HOME moet worden ingesteld op de locatie waar CppUTest is geïnstalleerd. Als u een distributiepakket hebt geïnstalleerd, bevindt dit zich meestal onder /usr/local op een linux/mac-systeem. Als u de repository zelf hebt uitgecheckt, is het waar die checkout is gedaan.

Deze opties zijn allemaal gedocumenteerd in MakefileWorker.mk.

MakefileWorker.mk voegt ook een paar makefile-doelstellingen toe, waaronder de volgende:

  1. all – bouwt de tests die door het makefile worden aangegeven

  2. clean – verwijdert alle gegenereerde object- en gcov-bestanden voor de tests

  3. realclean – verwijdert alle object- of gcov-bestanden in de gehele directorystructuur

  4. flags – geeft alle geconfigureerde flags weer die worden gebruikt om de tests te compileren

  5. debug – geeft alle bronbestanden, objecten, afhankelijkheden en 'schoon te maken onderdelen' weer

Code Dekking

Unit testing zou niet compleet zijn zonder een dekkingsrapport. Het standaardhulpmiddel hiervoor voor projecten die gcc gebruiken is gcov, beschikbaar als onderdeel van de standaard suite van gcc-hulpprogramma's. Cpputest integreert gemakkelijk met gcov, alles wat je hoeft te doen is deze regel aan het makefile toevoegen:

CPPUTEST_USE_GCOV=Y

Vervolgens moeten we ervoor zorgen dat het filterGcov.sh script uit deze repo in ‘/scripts/filterGcov.sh’ staat, relatief waar je ‘CPPUTEST_HOME’ hebt ingesteld. Het moet ook uitvoeringsrechten hebben.

In het voorbeeld Makefile zou het worden geïnstalleerd naar ‘/usr/local/scripts/filterGcov.sh’. Als je CppUTest vanaf een repo-checkout runt, zou alles zonder aanpassing moeten werken.

Met dat op zijn plaats, kun je eenvoudig ‘make gcov’ uitvoeren en de analyse zal voor jou worden gegenereerd. In ons geval moeten we ‘make -B’ gebruiken om de objectbestanden opnieuw te bouwen met gcov ingeschakeld:

[]$ make -B gcov
< compilation output >

for d in /Users/ykuperman/code/blogpost/qa/src/code ; do \
    FILES=`ls $d/*.c $d/*.cc $d/*.cpp 2> /dev/null` ; \
    gcov --object-directory objs/$d $FILES >> gcov_output.txt 2>>gcov_error.txt ; \
done

for f in  ; do \
    gcov --object-directory objs/$f $f >> gcov_output.txt 2>>gcov_error.txt ; \
done

/usr/local/scripts/filterGcov.sh gcov_output.txt gcov_error.txt gcov_report.txt example.txt

cat gcov_report.txt
100.00% /Users/ykuperman/code/blogpost/qa/src/code/code.cpp

mkdir -p gcov
mv *.gcov gcov
mv gcov_* gcov

See gcov directory for details

Dit zal een aantal bestanden naar een nieuwe ‘gcov’ directory uitvoeren. Deze zijn:

  1. code.cpp.gcov – het eigenlijke ‘gcov’ bestand voor de code die wordt getest

  2. gcov_error.txt – een foutenrapport (in ons geval zou het leeg moeten zijn)

  3. gcov_output.txt – de eigenlijke uitvoer van het gcov-commando dat is uitgevoerd

  4. gcov_report.txt – een samenvatting van de dekking voor elk getest bestand

  5. gcov_report.txt.html – een html-versie van gcov_report

Unit testing zou niet compleet zijn zonder een dekkingsrapport. Het standaardhulpmiddel hiervoor voor projecten die gcc gebruiken is gcov, beschikbaar als onderdeel van de standaard suite van gcc-hulpprogramma's. Cpputest integreert gemakkelijk met gcov, alles wat je hoeft te doen is deze regel aan het makefile toevoegen:

CPPUTEST_USE_GCOV=Y

Vervolgens moeten we ervoor zorgen dat het filterGcov.sh script uit deze repo in ‘/scripts/filterGcov.sh’ staat, relatief waar je ‘CPPUTEST_HOME’ hebt ingesteld. Het moet ook uitvoeringsrechten hebben.

In het voorbeeld Makefile zou het worden geïnstalleerd naar ‘/usr/local/scripts/filterGcov.sh’. Als je CppUTest vanaf een repo-checkout runt, zou alles zonder aanpassing moeten werken.

Met dat op zijn plaats, kun je eenvoudig ‘make gcov’ uitvoeren en de analyse zal voor jou worden gegenereerd. In ons geval moeten we ‘make -B’ gebruiken om de objectbestanden opnieuw te bouwen met gcov ingeschakeld:

[]$ make -B gcov
< compilation output >

for d in /Users/ykuperman/code/blogpost/qa/src/code ; do \
    FILES=`ls $d/*.c $d/*.cc $d/*.cpp 2> /dev/null` ; \
    gcov --object-directory objs/$d $FILES >> gcov_output.txt 2>>gcov_error.txt ; \
done

for f in  ; do \
    gcov --object-directory objs/$f $f >> gcov_output.txt 2>>gcov_error.txt ; \
done

/usr/local/scripts/filterGcov.sh gcov_output.txt gcov_error.txt gcov_report.txt example.txt

cat gcov_report.txt
100.00% /Users/ykuperman/code/blogpost/qa/src/code/code.cpp

mkdir -p gcov
mv *.gcov gcov
mv gcov_* gcov

See gcov directory for details

Dit zal een aantal bestanden naar een nieuwe ‘gcov’ directory uitvoeren. Deze zijn:

  1. code.cpp.gcov – het eigenlijke ‘gcov’ bestand voor de code die wordt getest

  2. gcov_error.txt – een foutenrapport (in ons geval zou het leeg moeten zijn)

  3. gcov_output.txt – de eigenlijke uitvoer van het gcov-commando dat is uitgevoerd

  4. gcov_report.txt – een samenvatting van de dekking voor elk getest bestand

  5. gcov_report.txt.html – een html-versie van gcov_report

Unit testing zou niet compleet zijn zonder een dekkingsrapport. Het standaardhulpmiddel hiervoor voor projecten die gcc gebruiken is gcov, beschikbaar als onderdeel van de standaard suite van gcc-hulpprogramma's. Cpputest integreert gemakkelijk met gcov, alles wat je hoeft te doen is deze regel aan het makefile toevoegen:

CPPUTEST_USE_GCOV=Y

Vervolgens moeten we ervoor zorgen dat het filterGcov.sh script uit deze repo in ‘/scripts/filterGcov.sh’ staat, relatief waar je ‘CPPUTEST_HOME’ hebt ingesteld. Het moet ook uitvoeringsrechten hebben.

In het voorbeeld Makefile zou het worden geïnstalleerd naar ‘/usr/local/scripts/filterGcov.sh’. Als je CppUTest vanaf een repo-checkout runt, zou alles zonder aanpassing moeten werken.

Met dat op zijn plaats, kun je eenvoudig ‘make gcov’ uitvoeren en de analyse zal voor jou worden gegenereerd. In ons geval moeten we ‘make -B’ gebruiken om de objectbestanden opnieuw te bouwen met gcov ingeschakeld:

[]$ make -B gcov
< compilation output >

for d in /Users/ykuperman/code/blogpost/qa/src/code ; do \
    FILES=`ls $d/*.c $d/*.cc $d/*.cpp 2> /dev/null` ; \
    gcov --object-directory objs/$d $FILES >> gcov_output.txt 2>>gcov_error.txt ; \
done

for f in  ; do \
    gcov --object-directory objs/$f $f >> gcov_output.txt 2>>gcov_error.txt ; \
done

/usr/local/scripts/filterGcov.sh gcov_output.txt gcov_error.txt gcov_report.txt example.txt

cat gcov_report.txt
100.00% /Users/ykuperman/code/blogpost/qa/src/code/code.cpp

mkdir -p gcov
mv *.gcov gcov
mv gcov_* gcov

See gcov directory for details

Dit zal een aantal bestanden naar een nieuwe ‘gcov’ directory uitvoeren. Deze zijn:

  1. code.cpp.gcov – het eigenlijke ‘gcov’ bestand voor de code die wordt getest

  2. gcov_error.txt – een foutenrapport (in ons geval zou het leeg moeten zijn)

  3. gcov_output.txt – de eigenlijke uitvoer van het gcov-commando dat is uitgevoerd

  4. gcov_report.txt – een samenvatting van de dekking voor elk getest bestand

  5. gcov_report.txt.html – een html-versie van gcov_report

Cpputest Geheugenlekdetectie

Cpputest stelt u in staat om automatisch gelekt geheugen te detecteren door de standaard 'malloc/free'-functie familietoepassingen te herdefiniëren om in plaats daarvan zijn eigen wrappers te gebruiken. Dit stelt het in staat om snel lekken te detecteren en te rapporteren voor elke testuitvoering. Dit is standaard ingeschakeld in MakefileWorker.mk, dus het is al actief met de stappen die tot nu toe zijn beschreven.

Om dit te illustreren, laten we wat geheugen lekken in test_func() !

Terug in code.c voegen we een malloc()  toe aan de functie, als volgt:

int test_func() {
    malloc(1);
    return 1;
}

Nu, na het opnieuw compileren, wordt de volgende fout geproduceerd:

test.cpp:9: error: Failure in TEST(AwesomeExamples, FirstExample)
Memory leak(s) found.
Alloc num (4)
Leak size: 1
Allocated at: ./code.c and line: 6
Type: "malloc"
Memory: <

Dit laat zien welke test het lek veroorzaakte, waar het lek in de broncode plaatsvond, en wat er in het gelekte geheugen stond. Heel nuttig!

Er zijn een paar kanttekeningen bij deze functie:

  1. Cpputest gebruikt preprocessor macro’s om alle oproepen aan de standaard geheugenbeheerfuncties dynamisch te herdefiniëren. Dat betekent dat het alleen zal werken voor oproepen in de te testen broncode, aangezien dat is wat met CppUTest's overschrijvingen wordt gecompileerd. Lekken in gekoppelde bibliotheken zullen niet worden opgevangen.

  2. Soms is geheugen dat voor de gehele levensduur van het proces is gealloceerd niet bedoeld om vrijgegeven te worden. Dit kan veel spamachtige fouten veroorzaken als je een module test met dit gedrag. Om de lekkagedetectie uit te schakelen, kunt u dit doen:

CPPUTEST_USE_MEM_LEAK_DETECTION=N

Cpputest stelt u in staat om automatisch gelekt geheugen te detecteren door de standaard 'malloc/free'-functie familietoepassingen te herdefiniëren om in plaats daarvan zijn eigen wrappers te gebruiken. Dit stelt het in staat om snel lekken te detecteren en te rapporteren voor elke testuitvoering. Dit is standaard ingeschakeld in MakefileWorker.mk, dus het is al actief met de stappen die tot nu toe zijn beschreven.

Om dit te illustreren, laten we wat geheugen lekken in test_func() !

Terug in code.c voegen we een malloc()  toe aan de functie, als volgt:

int test_func() {
    malloc(1);
    return 1;
}

Nu, na het opnieuw compileren, wordt de volgende fout geproduceerd:

test.cpp:9: error: Failure in TEST(AwesomeExamples, FirstExample)
Memory leak(s) found.
Alloc num (4)
Leak size: 1
Allocated at: ./code.c and line: 6
Type: "malloc"
Memory: <

Dit laat zien welke test het lek veroorzaakte, waar het lek in de broncode plaatsvond, en wat er in het gelekte geheugen stond. Heel nuttig!

Er zijn een paar kanttekeningen bij deze functie:

  1. Cpputest gebruikt preprocessor macro’s om alle oproepen aan de standaard geheugenbeheerfuncties dynamisch te herdefiniëren. Dat betekent dat het alleen zal werken voor oproepen in de te testen broncode, aangezien dat is wat met CppUTest's overschrijvingen wordt gecompileerd. Lekken in gekoppelde bibliotheken zullen niet worden opgevangen.

  2. Soms is geheugen dat voor de gehele levensduur van het proces is gealloceerd niet bedoeld om vrijgegeven te worden. Dit kan veel spamachtige fouten veroorzaken als je een module test met dit gedrag. Om de lekkagedetectie uit te schakelen, kunt u dit doen:

CPPUTEST_USE_MEM_LEAK_DETECTION=N

Cpputest stelt u in staat om automatisch gelekt geheugen te detecteren door de standaard 'malloc/free'-functie familietoepassingen te herdefiniëren om in plaats daarvan zijn eigen wrappers te gebruiken. Dit stelt het in staat om snel lekken te detecteren en te rapporteren voor elke testuitvoering. Dit is standaard ingeschakeld in MakefileWorker.mk, dus het is al actief met de stappen die tot nu toe zijn beschreven.

Om dit te illustreren, laten we wat geheugen lekken in test_func() !

Terug in code.c voegen we een malloc()  toe aan de functie, als volgt:

int test_func() {
    malloc(1);
    return 1;
}

Nu, na het opnieuw compileren, wordt de volgende fout geproduceerd:

test.cpp:9: error: Failure in TEST(AwesomeExamples, FirstExample)
Memory leak(s) found.
Alloc num (4)
Leak size: 1
Allocated at: ./code.c and line: 6
Type: "malloc"
Memory: <

Dit laat zien welke test het lek veroorzaakte, waar het lek in de broncode plaatsvond, en wat er in het gelekte geheugen stond. Heel nuttig!

Er zijn een paar kanttekeningen bij deze functie:

  1. Cpputest gebruikt preprocessor macro’s om alle oproepen aan de standaard geheugenbeheerfuncties dynamisch te herdefiniëren. Dat betekent dat het alleen zal werken voor oproepen in de te testen broncode, aangezien dat is wat met CppUTest's overschrijvingen wordt gecompileerd. Lekken in gekoppelde bibliotheken zullen niet worden opgevangen.

  2. Soms is geheugen dat voor de gehele levensduur van het proces is gealloceerd niet bedoeld om vrijgegeven te worden. Dit kan veel spamachtige fouten veroorzaken als je een module test met dit gedrag. Om de lekkagedetectie uit te schakelen, kunt u dit doen:

CPPUTEST_USE_MEM_LEAK_DETECTION=N

Geïnteresseerd in meer?

Dit is slechts het topje van de ijsberg als het gaat om alle functies die in deze tool zijn opgenomen. Naast de basis die hier wordt besproken, heeft het ook een mocking-framework, een directe C-integratielaag en een plugin-framework, om een paar belangrijke te noemen. De repo bevat ook een hele map met helper-scripts die kunnen helpen bij het automatiseren van enkele van de routinematige onderdelen van het werken met het framework.

Ik hoop dat de informatie hier je helpt de kwaliteit van je C/C++-code te verbeteren met deze geweldige tool!

Dit is slechts het topje van de ijsberg als het gaat om alle functies die in deze tool zijn opgenomen. Naast de basis die hier wordt besproken, heeft het ook een mocking-framework, een directe C-integratielaag en een plugin-framework, om een paar belangrijke te noemen. De repo bevat ook een hele map met helper-scripts die kunnen helpen bij het automatiseren van enkele van de routinematige onderdelen van het werken met het framework.

Ik hoop dat de informatie hier je helpt de kwaliteit van je C/C++-code te verbeteren met deze geweldige tool!

Dit is slechts het topje van de ijsberg als het gaat om alle functies die in deze tool zijn opgenomen. Naast de basis die hier wordt besproken, heeft het ook een mocking-framework, een directe C-integratielaag en een plugin-framework, om een paar belangrijke te noemen. De repo bevat ook een hele map met helper-scripts die kunnen helpen bij het automatiseren van enkele van de routinematige onderdelen van het werken met het framework.

Ik hoop dat de informatie hier je helpt de kwaliteit van je C/C++-code te verbeteren met deze geweldige tool!

Andere nieuws

Lees meer uit deze categorie

A person is standing at a desk while typing on a laptop.

Het complete AI-native platform dat met uw bedrijf meegroeit.

A person is standing at a desk while typing on a laptop.

Het complete AI-native platform dat met uw bedrijf meegroeit.