Jump to content

Entwicklung/UITests

From The Document Foundation Wiki
This page is a translated version of the page Development/UITests and the translation is 100% complete.

Dies ist die vorbereitende Dokumentation für den UI-Testrahmen mit speziellem Fokus auf der Phyton Seite.

Architektur

Das Testen der UI besteht aus zwei Teilen, einem C++-Teil, der die LibreOffice UI in einer selbstkotrolierender Library mit einem Phyton Rahmen mit dem aktuellen Test-Code verbindet. Die Verbindung zwischen den beiden Teilen ist mit einem simplen meist nicht typisiertem UNO Interface verwirklicht.

C++ selbstkontrollierende Library

Die C++ selbstkontrollierende Library besteht aus einer UNO API die für die Kommunikation zwischen dem Phyton Teil des Rahmens und dem Wrapper für viele UI Instanzen zuständig ist. Das UNO Interface hat nur ein paar Methoden und meistens findet die Kommunikation durch Text-Paramter statt.

Der Wrapper für die UI Instanzen bietet die selben Methoden wie das UNO Interface plus einiger Hilfsmethoden.

Pyhton Rahmen

Tests erstellen

Xisco Faulis Präsentation von der FOSDEM 2021 LibreOffice QA - how to write your first test geht durch den Prozess der Testerstellung.

Xiscos Präsentation von der FOSDEM 2022 zeigt Things you can test in a UITest.

Das Makefile

Ein einfaches Makefile für den Test des UI sieht in etwa wie folgt aus: das Makefile-Demo. Der wichtigste Teil dabei ist die UITest gbuild class und dass das gb_UITest_add_module auf die Verzeichnisse mit den Testdateien zeigt.

Normalerweise ist sonst nichts nötig und meistens wird die gbuild UITest Klasse genutzt.

$(eval $(call gb_UITest_UITest,range_name))

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

Der Parameter Bereichs-Name ist der Name des Test-Ziels. $(SRCDIR/sc/qa/uitest ist das Wurzel-Verzeichnis und die Parameter in diesem Teil beinhaltet die Verzeichnisse für die Tests.

Optional kann der Test auch mit einer bestimmten registrymodifications.xcu Datei gestartet werden, um eine spezielle Konfiguration vorzugeben. Jeder Test hat sein eigenes User Profil in workdir/UITest/test_name/user/. Mit dem folgenden Makefile Schnippsel kann eine Datei in dieses Verzeichnis kopiert werden.

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

Dabei wird die Datei sc/qa/uitest/range_name/registrymodifications.xcu ins User Profil kopiert und der Test wird mit diesen Einstellungen durchgeführt.

Erstellung des Python Codes

Infrastruktur

Kommandos für UI Elemente

Generisch

Status für UI-Instanzen

Die Methode zur Ermitlung des Status wird von allen UI Elementen zur Verfügung gestellt. Die Methode gibt den Status als Sequenz von PropertyValues zurück.

ui_element.getState()

Das UI-Test-Framework stellt eine Methode zur Verfügung, die die zurückgegebene Sequenz von ValueProperties in ein Python Verzeichnis konvertiert.

from uitest.uihelper.common import get_state_as_dict

get_state_as_dict(ui_element)

Tastatureingabe an ein Element übergeben

from uitest.uihelper.common import type_text

xWriterDoc = self.xUITest.getTopFocusWindow()
xWriterEdit = xWriterDoc.getChild("writer_edit")
type_text(xWriterEdit, "Test")

Text auswählen

from uitest.uihelper.common import select_text

xEdit = xAddNameDlg.getChild("edit")
select_text(xEdit, from_pos="2", to="12")

Vergrösserung einstellen

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

auf eine Seite wechseln

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

Steuerbefehle

Steuerung Code Ausdruck
Button

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

---

TextBox

from uitest.uihelper.common import type_pos

type_text(xControl, "Text")

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

CheckBox

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

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

Schriftsatz Widget

from libreoffice.uno.propertyvalue import mkPropertyValues

xControl.executeAction("SELECT", mkPropertyValues({"COLUMN": "2", "ROW": "2"}))

---

Baum Liste

# Baum auf-/zuklappen
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 (Position)

from uitest.uihelper.common import select_pos

select_pos(xListBox, "1")

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

ListBox (Name)

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")

Tabdialog (Name)

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

---

Spinfield

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

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

Radiobutton

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

---


Keyword Aktionen

Beispiel:

from libreoffice.uno.propertyvalue import mkPropertyValues

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

Schlüsselwörter:

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

Wie wird die introspection Library erweitert

UI Elemente, die das vcl::Window erweitern

andere UI Elemente

Tools zur Erstellung eines Tests

Die Schwierigkeit beim Testen besteht darin, welche Kommandos gesendet werden sollen und welche Aktion auf einer UI ausgelöst werden soll. Glücklicherweise ist es möglich, die UNO Kommandos zu protokollieren.

  1. Nutzen Sie diese Zeilen in .bashrc oder .cshrc:
    export PYTHONPATH=/"Pfad zum LibreOffice Datenspeicher"/instdir/program/
    export URE_BOOTSTRAP=file:///"Path of LibreOffice repo"/instdir/program/fundamentalrc
  2. LibreOffice folgendermaßen starten:
    LO_COLLECT_UIINFO="test.log" SAL_USE_VCLPLUGIN=gen instdir/program/soffice
    Hinweis: "LO_COLLECT_UIINFO" ist ein relativer Pfad unter "instdir/uitest/".
  3. Aktivitäten mit der Maus durchführen
  4. LibreOffice schließen
  5. die Ergebnisdatei in instdir/uitest/test.log öffnen
  6. ins UI Protokoll Verzeichnis wie folgt wechseln:
    cd uitest/ui_logger_dsl/
  7. Sicherstellen, dass textX library installiert wurde
  8. folgendes Kommando ausführen
    python dsl_core.py <Pfad_zur_Protokolldatei> <Pfad_zu_einer_neuen_Phyton_Datei>
    <Pfad_zur_Protokolldatei> sollte mit SourceDirectory/core/instdir/uitest/test.log oder so etwas ähnlichem ersetzt werden und <Pfad_zu_einer_neuen_Phyton_Datei> kann ein Ort Ihrer Wahl sein, an dem der generierte Code landen sollte.

All diese Schritte können in diesem YouTube Video nachvollzogen werden:

Bitte akzeptieren Sie dieses Video. Dadurch gelangen Sie an Inhalt von YouTube, einem Service, der von einer dritten Partei bereitgestellt wird.

YouTube privacy policy


Testausführung

Bevor der Test gestartet wird, sollte sichergestellt werden, dass er funktioniert. Eine einfache Möglichkeit, alle UI-Tests im UI-Modul auszuführen, ist es, uitest.uicheck auszuführen. So können wir das UI sehen, während der Test läuft und die Tests laufen einfach durch. Dies wird erreicht, indem der Test in folgendem Core-Verzeichnis ausgeführt wird:

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

Es ist auch möglich, ein Shellskript zu verwenden, um den Test zu starten.

Dieses Skript muss im Quellverzeichnis des LibreOffice Cores laufen.

Es können auch ein paar Umgebungsvariablen nötig sein, damit das Skript funktioniert. Daher lautet das vollständige Skript wie folgt:

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

Im Fall, dass der Test get_url_for_data_file aufruft, um eine Datei zu öffnen, ändern Sie bitte die Variable TDOC auf das Verzeichnis, in dem die Datei liegt. Wenn Sie den Test bei sichtbarem UI ausführen, werden Sie feststellen, dass der Test zu schnell läuft, um festzustellen, was vor sich geht. Eine Quick and Dirty Lösung wäre, in Pyhton time.sleep(10) zu ergänzen. Das stoppt die Ausführung ein wenig. Die andere Lösung wäre, im Code an interessanten Stellen uitest.debug.sleep zu verwenden. Bitte verwenden Sie nur ein paar nützliche Stellen im Test. Diese Methode wird ignoriert, bis der Test im Debug-Modus läuft, indem der Test mit dem Parameter --debug gestartet wird.

Falls Sie nur einen Test im Test-Skript brauchen, verwenden Sie folgendes Kommando:

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

zum Beispiel

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


nicht unterstützte UI Bestandteile

  • Base Support
  • Folien sortieren in Impress
  • Doppelklick in Formulare. Siehe tdf#133641 für Ideen
  • Datei-Assistenten
  • Impress - Präsentationsminimierung
  • Protokollierung (LO_COLLECT_UIINFO) unter Windows
  • Doppelklick
  • Grafik-Protokollierung
  • untere Info-Toolbar in Calc
  • besserer Support für Shortcuts (tdf#124931)

Liste der UI Tests im Master

Siehe die Liste der bereits implementierten UITests.

Fehler finden

In Bugzilla gibt es das Schlüsselwort needUITest um alle Fehler aufzulisten, die einen automatischen UITest erfordern:

Weitere Informationen