Sviluppo/Test dell'interfaccia utente (UI)

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

    Questa è la documentazione preliminare per il framework di test dell'interfaccia utente, con un'attenzione particolare alla parte Python

    Architettura

    Il testing dell'interfaccia utente è composto da due parti: una componente in C++ che avvolge l'interfaccia utente di LibreOffice in una libreria di introspezione e un framework Python con il codice di test vero e proprio. La connessione tra le due parti avviene tramite una semplice interfaccia UNO, per lo più non tipizzata

    Libreria di introspezione C++

    La libreria di introspezione C++ consiste in un'API UNO che viene utilizzata per la comunicazione con la parte Python del framework e in wrapper per molti oggetti dell'interfaccia utente. L'interfaccia UNO ha solo alcuni metodi e la maggior parte della comunicazione avviene tramite parametri di tipo stringa.

    Il wrapper per gli oggetti dell'interfaccia utente fornisce circa gli stessi metodi dell'interfaccia UNO, con l'aggiunta di alcuni metodi di supporto.

    Framework Python

    Scrittura dei test

    Xisco Faulí's presentation from FOSDEM 2021, LibreOffice QA - how to write your first test, walks through the process of creating tests.

    Xisco's presentation from FOSDEM 2022 shows Things you can test in a UITest.

    Makefile

    A simple makefile for the UI testing looks like the demo makefile. The important part is to use the UITest gbuild class and let the gb_UITest_add_module point to the directories with test files.

    Normalmente non è richiesto nient'altro, poiché la maggior parte delle operazioni viene gestita dalla classe gbuild UITest.

    $(eval $(call gb_UITest_UITest,range_name))
    
    $(eval $(call gb_UITest_add_modules,range_name,$(SRCDIR)/sc/qa/uitest,\
        test_dir1/ \
        test_dir2/ \
    ))

    Il parametro range_name è il nome del target del test. La parte $(SRCDIR/sc/qa/uitest) è la directory di base e i parametri in quella parte elencano le directory in cui cercare i test.

    In alternativa, è possibile eseguire il test con un file specifico registrymodifications.xcu per supportare l'esecuzione con impostazioni di configurazione personalizzate. Ogni test dispone di un proprio profilo utente nella directory workdir/UITest/test_name/user/. Con il seguente frammento di makefile, è possibile copiare un file all'interno di questa directory.

    $(eval $(call gb_UITest_use_configuration,range_name,$(SRCDIR)/sc/qa/uitest/range_name/registrymodifications.xcu))

    Questo comando copierebbe il file sc/qa/uitest/range_name/registrymodifications.xcu nel profilo utente e il test verrebbe eseguito con queste impostazioni.

    Scrittura del codice Python

    Infrastruttura

    Comandi disponibili sugli elementi dell'interfaccia utente

    Generico

    Gestione dello stato degli oggetti UI

    Il metodo per ottenere lo stato dell'oggetto UI è fornito da tutti gli elementi UI. Il metodo restituisce lo stato come una sequenza di PropertyValue.

    ui_element.getState()

    Il framework di test UI fornisce un metodo per convertire la sequenza restituita di PropertyValue in un dizionario Python.

    from uitest.uihelper.common import get_state_as_dict
    
    get_state_as_dict(ui_element)

    Inviare input da tastiera a un elemento

    from uitest.uihelper.common import type_text
    
    xWriterDoc = self.xUITest.getTopFocusWindow()
    xWriterEdit = xWriterDoc.getChild("writer_edit")
    type_text(xWriterEdit, "Test")

    Selezionare il testo

    from uitest.uihelper.common import select_text
    
    xEdit = xAddNameDlg.getChild("edit")
    select_text(xEdit, from_pos="2", to="12")

    Impostare lo zoom

    xWriterEdit = xWriterDoc.getChild("writer_edit")
    xWriterEdit.executeAction("SET", mkPropertyValues({"ZOOM": "200"}))


    Andate alla pagina

    xWriterEdit = xWriterDoc.getChild("writer_edit")
    xWriterEdit.executeAction("GOTO", mkPropertyValues({"PAGE": "1"}))

    Azioni di Controllo

    Controllo Codice Asserzione
    Bottone

    xControl.executeAction("CLICK", tuple())

    ---

    Casella di testo

    from uitest.uihelper.common import type_pos
    
    type_text(xControl, "Text")

    self.assertEqual(get_state_as_dict(xTitleText)["Text"], "Text")

    Casella di controllo

    xControl.executeAction("CLICK", tuple())

    self.assertEqual(get_state_as_dict(xControl)["Selected"], "true")

    Widget della mappa dei caratteri

    from libreoffice.uno.propertyvalue import mkPropertyValues
    
    xControl.executeAction("SELECT", mkPropertyValues({"COLUMN": "2", "ROW": "2"}))

    ---

    Elenco degli alberi

    # Espandere/Restringere l'albero
    xTreelist = xExDBDlg.getChild("availablelb")         
    xTreeEntry = xTreelist.getChild('0')
    xTreeEntry.executeAction("EXPAND", tuple())  #Available Databases
    xTreeEntry.executeAction("COLLAPSE", tuple()) #Click on the Bibliography
    
    xTreeEntry2 = xTreeEntry.getChild('0')
    xTreeEntry2.executeAction("SELECT", tuple())

    ---

    ComboBox

    from uitest.uihelper.common import select_pos
    
    select_pos(xCombobox, "1")

    self.assertEqual(get_state_as_dict(xNumbering)["SelectEntryText"], "List 1")

    Tabs

    from uitest.uihelper.common import select_pos
    
    xTabs = xDialog.getChild("tabcontrol")
    select_pos(xTabs, "0")

    self.assertEqual(get_state_as_dict(xTabs)["CurrPagePos"], "0")

    ListBox(per posizione)

    from uitest.uihelper.common import select_pos
    
    select_pos(xListBox, "1")

    self.assertEqual(get_state_as_dict(xListBox)["SelectEntryText"], "List 1")

    Casella elenco (per nome

    from uitest.uihelper.common import select_pos
    
    categoryLB = xCellsDlg.getChild("categorylb")
            props = {"TEXT": "Time"}
    
    actionProps = mkPropertyValues(props)
            categoryLB.executeAction("SELECT", actionProps)

    self.assertEqual(get_state_as_dict(categoryLB)["SelectEntryText"], "Time")

    Finestra a schede (per nome)

    props = {"NAME": "Borders"}
            propsUNO = mkPropertyValues(props)
            xCellsDlg.executeAction("SELECT", propsUNO)

    ---

    Campo di selezione numerica

    xDecimalPlaces.executeAction("UP", tuple())
    xDecimalPlaces.executeAction("DOWN", tuple())

    self.assertEqual(get_state_as_dict(xDecimalPlaces)["Text"], "Title text")

    Pulsante di opzione

    xSuperscript.executeAction("CLICK", tuple())

    self.assertEqual(get_state_as_dict(xSuperscript)["Checked"], "true")

    ColorListBox

    xWidget.executeAction("OPENLIST", tuple())
    xFloatWindow = self.xUITest.getFloatWindow()
    xPaletteSelector = xFloatWindow.getChild("palette_listbox")
    select_by_text(xPaletteSelector, "chart-palettes")  # or some other name
    xColorSet = xFloatWindow.getChild("colorset")
    xColorSet.executeAction("CHOOSE", mkPropertyValues({"POS": "2"}))  # or some other position

    ---

    MenuButton

    xWidget.executeAction("OPENFROMLIST", mkPropertyValues({"POS": "0"}))

    ---


    Azione della parola chiave

    Esempio/Campione

    from libreoffice.uno.propertyvalue import mkPropertyValues
    
    ui_object.executeAction("TYPE", mkPropertyValues({"KEYCODE":"CTRL+A"}))

    Codice chiave

    • ESC
    • TAB
    • DOWN
    • UP
    • LEFT
    • RIGHT
    • DELETE
    • INSERT
    • BACKSPACE
    • RETURN
    • HOME
    • END
    • PAGEUP
    • PAGEDOWN
    • CTRL
    • ALT
    • SHIFT

    Come estendere la libreria di introspezione

    Estensione degli elementi UI che estendono vcl::Window

    Altri elementi UI

    Strumenti per scrivere un test

    La parte difficile nello scrivere un test è capire quali comandi UNO inviare e quale azione chiamare su un oggetto dell'interfaccia utente. Fortunatamente, è possibile registrare i comandi UNO

    1. Usa queste righe in .bashrc o .cshrc:
      export PYTHONPATH=/"Percorso del repository di LibreOffice"/instdir/program/
      export URE_BOOTSTRAP=file:///"Path of LibreOffice repo"/instdir/program/fundamentalrc
    2. Avvia LibreOffice con
      LO_COLLECT_UIINFO="test.log" SAL_USE_VCLPLUGIN=gen instdir/program/soffice
      Note: "LO_COLLECT_UIINFO" is a relative path under "instdir/uitest/".
    3. Simula ciò che vuoi fare con il mouse
    4. Chiudi LibreOffice
    5. Apri il file risultante in instdir/uitest/test.log
    6. Accedi alla directory del registratore dell'interfaccia utente con questo comando:
      cd uitest/ui_logger_dsl/
    7. Make sure that your python has textX library installed
    8. Usa il seguente comando
      python dsl_core.py <percorso_del_file_di_log> <percorso_del_nuovo_file_python>
      <percorso_del_file_di_log> deve essere sostituito con qualcosa come SourceDirectory/core/instdir/uitest/test.log e <percorso_del_nuovo_file_python> può essere una posizione a tua scelta dove desideri vedere il codice generato.

    Puoi seguire tutti questi passaggi in questo video di YouTube

    Siete pregati di accettare questo video. Accettando si accederà ai contenuti di YouTube, un servizio fornito da una terza parte esterna.

    YouTube privacy policy


    Eseguire il test

    Prima di spingere il test su master, dobbiamo ovviamente verificare che il test funzioni. Un modo semplice è eseguire tutti i test dell'interfaccia utente nel modulo uitest tramite il comando make uitest.uicheck. Tuttavia, vorremmo vedere l'interfaccia utente mentre il test viene eseguito, e i test vengono eseguiti in modalità headless per impostazione predefinita. Questo si ottiene eseguendo il seguente comando nella directory core:

    (cd sc && make -srj1 UITest_sort UITEST_TEST_NAME="sorting.CalcSorting.test_Sortingbuttons_detect_columnheaders" SAL_USE_VCLPLUGIN=gen)

    It is also possible to use a shell script for starting a test.

    Nota che devi eseguire questo script dalla directory di origine del core di LibreOffice.

    Potrebbero essere necessarie anche alcune variabili d'ambiente per farlo funzionare, quindi lo script completo sarebbe del tipo:

    export SRCDIR=$PWD
    export PYTHONPATH=$SRCDIR/instdir/program:unotest/source/python
    export URE_BOOTSTRAP=file://$SRCDIR/instdir/program/fundamentalrc
    export TestUserDir=file:///tmp
    export TDOC=$SRCDIR/sw/qa/uitest/data
    export SAL_USE_VCLPLUGIN=gen
    export LC_ALL=C
    
    rm -rf /tmp/libreoffice/4
    
    python3 "$SRCDIR"/uitest/test_main.py --soffice=path:"$SRCDIR"/instdir/program/soffice --userdir=file:///tmp/libreoffice/4 --file="$SRCDIR"/sc/qa/uitest/sort/sorting.py

    Nel caso in cui il test chiami get_url_for_data_file per aprire un file, modificare di conseguenza la variabile TDOC per puntare alla directory in cui si trova il file. Quando si esegue il test con l'interfaccia utente visibile, si noterà che il test è troppo veloce per vedere cosa sta succedendo. Una soluzione rapida e sporca è quella di aggiungere a python (import time) time.sleep(10), che interrompe l'esecuzione per un po'. L'altra soluzione che si può effettivamente lasciare nel codice (solo pochi utili in un test) in posti interessanti è uitest.debug.sleep. Questo metodo viene ignorato a meno che il test non venga avviato in modalità debug, passando il parametro --debug al test.

    Quando è necessario eseguire un solo test nel file di script di test, eseguire il comando seguente:

    UITEST_TEST_NAME="FILENAME.CLASS_NAME.TEST_NAME" ./execute.sh

    Per esempio

    UITEST_TEST_NAME="sorting.CalcSorting.test_Sortingbuttons_detect_columnheaders" ./execute.sh


    Elementi dell'interfaccia utente non supportati

    • Supporto di base
    • Selezionatore di diapositive in Impress
    • Double-clicking on forms. See tdf#133641 for inspiration
    • File - wizard
    • Impress - Minimizzatore di presentazioni
    • Registrazione ( LO_COLLECT_UIINFO) in Windows
    • Doppio click
    • registrazione dei grafici
    • barra degli strumenti inferiore di Calc
    • better support for shortcuts (tdf#124931)

    Elenco dei test dell'interfaccia utente nel master

    Potete consultare la lista dei UItest già implementati.

    Trovare errori

    Abbiamo la parola chiave needUITest in Bugzilla per tracciare tutti i bug che necessitano di un UITest per essere testati automaticamente:

    Ulteriori informazioni