Jump to content

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 100% complete.

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

Architettura

La prova dell'interfaccia utente è composta 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 i 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

Prove di scrittura

La presentazione di Xisco Faulí al FOSDEM 2021, LibreOffice QA - come scrivere il vostro primo test, in inglese, illustra il processo di creazione dei test.

La presentazione di Xisco al FOSDEM 2022 mostra Cose che potete testare in un UITest, in inglese.

Parte di un makefile

Un semplice makefile per il test dell'interfaccia utente è simile a il makefile demo, in inglese. La parte importante è usare la classe gbuild UITest e lasciare che gb_UITest_add_module punti alle directory con i file di test.

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.

Scrivere il 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"}))


Andare 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())

---

Casella combinata

from uitest.uihelper.common import select_pos

select_pos(xCombobox, "1")

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

Tabulazioni

from uitest.uihelper.common import select_pos

xTabs = xDialog.getChild("tabcontrol")
select_pos(xTabs, "0")

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

Casella elenco (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"}))

---


Azioni con parola chiave

Esempio:

from libreoffice.uno.propertyvalue import mkPropertyValues

ui_object.executeAction("TYPE", mkPropertyValues({"KEYCODE":"CTRL+A"}))

CODICI 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. Usate 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. Avviate LibreOffice con
    LO_COLLECT_UIINFO="test.log" SAL_USE_VCLPLUGIN=gen instdir/program/soffice
    Nota: "LO_COLLECT_UIINFO" è un percorso relativo sotto "instdir/uitest/".
  3. Simula ciò che volete fare con il mouse
  4. Chiudete LibreOffice
  5. Aprite il file risultante in instdir/uitest/test.log
  6. Accedete alla directory del registratore dell'interfaccia utente con questo comando:
    cd uitest/ui_logger_dsl/
  7. Assicuratevi che il vostro python abbia installato textX library
  8. Usate 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 vostra scelta dove desideriate vedere il codice generato.

Potete 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à senza intestazione 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)

È anche possibile utilizzare uno script da shell per avviare un test.

Nota che dovete 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, modificate di conseguenza la variabile TDOC per puntare alla directory in cui si trova il file. Quando eseguite il test con l'interfaccia utente visibile, noterete che il test è troppo veloce per vedere cosa sta succedendo. Una soluzione rapida e non corretta è quella di aggiungere a python (import time) time.sleep(10), che interrompe l'esecuzione per un po'. L'altra soluzione che potete effettivamente lasciare nel codice in posti di interesse (solo in pochi punti utili in un test) è 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, eseguite 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
  • Doppio clic sui formulari. Si veda per ispirazione tdf#133641
  • File - creazione guidata
  • Impress - Minimizzatore di presentazioni
  • Registrazione ( LO_COLLECT_UIINFO) in Windows
  • Doppio clic
  • registrazione dei grafici
  • barra inferiore degli strumenti di Calc
  • maggior supporto per le scorciatoie (tdf#124931)

Elenco dei test dell'interfaccia utente nel master

Potete consultare la lista dei UItest già implementati.

Trovare bug

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

Ulteriori informazioni