Udvikling/Tests med Cpp Unit
TDF LibreOffice Document Liberation Project Community Blogs Weblate Nextcloud Redmine Ask LibreOffice Donate
CppUnit
LibreOffice bruger CppUnit-rammen til sine afprøvninger af C++-enheder. CppUnit er e C++-port til JUnit-rammen og er blevet forgrenet flere gange. LibreOffice vedligeholder sin egen forgrening af CppUnit, som i dag er den sidste aktive forgrening.
Xisco Faulí's præsentation from FOSDEM 2021, LibreOffice QA - sådan skriver du dine første tests går med dig gennem processen med at oprette tests.
Typer af enheds-tests i LibreOffice-koden
Der er mange typer af enhedstest i LibreOffice. Hvis du er usikker på, hvilken du skal bruge, spørg venligst på postlisten LibreOffice development eller på IRCen - se "Talk to developers" på https://www.libreoffice.org/community/developers/ .
Test en funktion/metode
Tag funktionen/metoden og fød den med forskellige data og vurder, om resultatet er korrekt.
Eksempel: test::oustring::StringConcat::checkConcat() på https://cgit.freedesktop.org/libreoffice/core/tree/sal/qa/rtl/strings/test_oustring_concat.cxx#n57
Import-test
Til en import-test er to ting nødvendige:
- et test-dokument - en minimeret version af det dokument, som viste fejlen for første gang. Det er bedst, hvis du kan genskabe dokumentet helt forfra for at undgå fortrolige data i det. Tjek lignende tests på det sted, hvor dokumentet skulle gemmes, sædvanligvis er det i en 'data/'-undermappe.
- selve testen
Import-testen indlæser så dokumentet som det første, og derefter vurderer du, præcist hvlken egenskab, der blev rettet.
Eksempel: testFdo50665 på https://cgit.freedesktop.org/libreoffice/core/tree/sw/qa/extras/rtfimport/rtfimport.cxx#n606
Eksport-test
Eksport-testen udvider import-testen ved faktisk at gen-importere to gange:
- første gang bliver dokumentet læst, og så gemt med det filter, vi vil teste, og
- anden gang bliver det gemte resultat indlæst igen for at vurdere, om lagringen blev udført korrekt.
Vurderingen af det gemte resultat kan gøres på samme måde som i import-testen (se ovenfor) eller ved at bruge assertXPath-metoden (se nedenfor).
Ekswmpel: testDMLSolidfillAlpha på https://cgit.freedesktop.org/libreoffice/core/tree/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx#n115
assertXPath-test
I mange tilfælde arbejder vi på XML:
- ODF og OOXML er XML i en indpakning
- vi dumper data som XML (med forskelligt debugging-output - som Writer layout-dumpet, EMF/WMF-struktur, XShapes osv.)
Tricket er så at indlæse data som DOM og vurdere forskellige egenskaber gennem et XPath-udtryk.
Eksempel: testBehinddoc på https://cgit.freedesktop.org/libreoffice/core/tree/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx#n610
EMF/WMF-eksempler: https://cgit.freedesktop.org/libreoffice/core/tree/emfio/qa/cppunit/wmf/wmfimporttest.cxx
Enheds-tests dumper et bitmap og resultatet vurderes
EMF+ gemmes i EMF-kommentarer og gengives senere. For at være i stand til at teste dette er det nødvendigt at dumpe det som et bitmap og vurdere, om de forskellige pixels har de rette værdier.
For at dumpe bitmappet først (for at se, hvad du helt præcist vil vurdere) eksporterer du CPPCANVAS_DEBUG_EMFPLUS_DUMP_TO=/tmp/file.png , og bitmappet bliver gemt i /tmp/file.png , når du udfører enhedstesten.
Eksempel: https://cgit.freedesktop.org/libreoffice/core/tree/cppcanvas/qa/extras/emfplus/emfplus.cxx
Layout dump-test
Dette er specifikt for Writer. I nogle tilfælde er det nødvendigt at teste, hvordan dokumentet blev lay-out'et af lay-out-motoren - fx. skulle noget tekst vises på 3. side, mens det tidligere er blevet vist på anden siden og lignende.
Disse tests virker sådan, at filen importeres og layoutet derefter dumpes som XML.
Eksempel: testFdo52052 på https://cgit.freedesktop.org/libreoffice/core/tree/sw/qa/extras/rtfimport/rtfimport.cxx#n755 .
XShape-test
Denne kan let bruges i chart2 eller Impress. Visningens struktur (det er det, der præsenteres somXShapes hierarki) dumpes som XML, og sammenlignes derefter enten med et reference-dump (mindre pålideligt - da dump-metoden kan ændres i fremtiden) eller tjekkes med assetXpath (den nye metode).
Eksempel (reference): Chart2XShapeTest::testFdo75075() på https://cgit.freedesktop.org/libreoffice/core/tree/chart2/qa/extras/xshape/chart2xshape.cxx#n80
Eksempel (assertXPath): Chart2XShapeTest::testTdf76649TrendLineBug() på https://cgit.freedesktop.org/libreoffice/core/tree/chart2/qa/extras/xshape/chart2xshape.cxx#n144
Komplekst scenarie-test
Det kan ske, at en fejl har brug for adskillige trin for at kunne reproduceres. Selv det kan testes, når proceduren er pålidelig.
I disse tilfælde er det sædvanligvis en import-test med yderligere trin, som skal gøres - som at markere tekst og udløse en reaktion på det, osv.
Eksempel: testFdo37606Copy på https://cgit.freedesktop.org/libreoffice/core/tree/sw/qa/extras/odfimport/odfimport.cxx#n738
LibreOfficeKit (LOK)-test
Nogle funktionaliteter (som at trykke på en tast som om det var et rigtigt tastatur-input) er mulige gennem LibreOfficeKit API, men ikke gennem UNO eller det interne API (fx. fordi SwEditWin i Writer ikke er en 'public class' set fra et synlighedssynspunkt).
Hvis du vil bruge det, skal du få fat i oversigt over implementeringen af UNO-objektet, som repræsenterer et dokument. Derefter kan du kalde dets element-funktioner direkte.
Eksempel: testTdf89954 på https://cgit.freedesktop.org/libreoffice/core/tree/sw/qa/extras/uiwriter/uiwriter.cxx#n2371
Hastighedstests
Disse tests udføre som del af make perfcheck. De kræver, at valgrind-dev-pakken er installeret. De generer log-filer i workdir/CppunitTest/[testname]/.., som inddeholder valgrind-log-fier..
De kan behandles til at producere en summmarisk CSV-fil med bin/parse-perfcheck.py
Eksempel: sc/qa/perf/scperfobj.cxx
Tilføj en ny test
I nogle tilfælde er enheds-testenes infrastruktur endnu ikke introduceret. I disse tilfælde find venligst inspiration på områder, som har masser af enheds-tests, og opret den nye test på denne måde.
Opdagelse af en teststrategi
Du kører måske LibreOffice i en debugger og indsætter et stoppunkt i en relevant del af fejlrettelsen. Derefter gør du manuelt det, der plejede at udløse fejlen og inspicerer den backtrace, debuggeren har leveret. Endelig kalder du i din cppunit-test den lignende funktion, for at se hvordan du kaldte den i backtracen.
Definer test-klassen
Testene skal placeres i undermappen qa/
i en fil med navnet test_xxx.cxx
. Først skal du oprette din test-klasse. Her følger et muligt, grundliggende test-skelet:
// copy here a header from the file TEMPLATE.SOURCECODE.HEADER in the root of the source tree.
#include "sal/config.h"
#include "sal/precppunit.hxx"
#include "cppunit/TestAssert.h"
#include "cppunit/TestFixture.h"
#include "cppunit/extensions/HelperMacros.h"
#include "cppunit/plugin/TestPlugIn.h"
namespace
{
/**
* Perform tests on MyClass.
*/
class MyClassTest : public CppUnit::TestFixture
{
private:
/**
* Tests capability Foo of the class.
*/
void testFoo();
// Adds code needed to register the test suite
CPPUNIT_TEST_SUITE(MyClassTest);
// Declares the method as a test to call
CPPUNIT_TEST(testFoo);
// End of test suite definition
CPPUNIT_TEST_SUITE_END();
};
void MyClassTest::testFoo()
{
CPPUNIT_ASSERT(true); // do the tests here
}
// Put the test suite in the registry
CPPUNIT_TEST_SUITE_REGISTRATION(MyClassTest);
} // namespace
CPPUNIT_PLUGIN_IMPLEMENT();
Skriv en eller flere test-funktioner og test klassens forskellige potentialer. Find flere oplysninger om at teste med CppUnit iCppUnit-øvelser .
Kør test under bygningen
Nu din test-klasse er færdig, skal du kompilere og køre den. Derfor opretter du filen CppunitTest_module_test.mk
(erstat modul- og test-navn med det passende) på øverste (komponent) mappeniveau, hvis det ikke allerede eksisterer.
# copy here a header from the file TEMPLATE.SOURCECODE.HEADER in the root of the source tree.
$(eval $(call gb_CppunitTest_CppunitTest,module_test))
$(eval $(call gb_CppunitTest_add_exception_objects,module_test, \
module/qa/cppunit/test_xxx \
))
# add a list of all needed libraries here
$(eval $(call gb_CppunitTest_add_linked_libs,module_test, \
sal \
$(gb_STDLIBS) \
))
$(eval $(call gb_CppunitTest_set_include,module_test,\
$$(INCLUDE) \
-I$(OUTDIR)/inc \
))
Du skal også redigere Module_module.mk
og tilføje følgende (eller tilføje det på listen, hvis den allerede findes):
$(eval $(call gb_Module_add_check_targets,module,\
CppunitTest_module_test \
))
For at bygge og køre testene, kører du simpelthen make check
. hvis bygget lykkes, kører testene automatisk.
Så, når dine tests kører, er alt, du skal gøre at rette de fejl, de afslører.
Kør en enkelt test ad gangen
CPPUNIT_TEST_NAME er den miljø-variabel, som skal sættes og indeholde testenes navn. Test-navne skal være fuldt kvalificerede for at blive genkendt.
Eksempel:
CPPUNIT_TEST_NAME="testOutlineODS testPrintRangeODS" make CppunitTest_sc_subsequent_filters_test2
Printing to stderr is hidden if the test passes and displayed if it fails.
If you use a single string as a value of CPPUNIT_TEST_NAME, that has to be a class name. If that class has multiple tests, then all tests inside that class will be ran. The CPPUNIT_TEST_FIXTURE macro always creates a class with a single test function.
You can discover the make targets by looking at the *.mk files in modules.