Udvikling/Tests med Cpp Unit

    From The Document Foundation Wiki
    This page is a translated version of the page Development/Cpp Unit Tests and the translation is 98% complete.
    Outdated translations are marked like this.
    Other languages:

    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()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: testFdo50665https://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: testDMLSolidfillAlphahttps://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: testBehinddochttps://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: testFdo52052https://cgit.freedesktop.org/libreoffice/core/tree/sw/qa/extras/rtfimport/rtfimport.cxx#n755 .

    Flere oplysninger

    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()https://cgit.freedesktop.org/libreoffice/core/tree/chart2/qa/extras/xshape/chart2xshape.cxx#n80

    Eksempel (assertXPath): Chart2XShapeTest::testTdf76649TrendLineBug()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: testFdo37606Copyhttps://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: testTdf89954https://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.

    Eksempler:

    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.