Wenn die Anzahl der Tests in einem Projekt zunimmt, wird die CI-Rotation langsamer und die Belastung steigt, wenn die Tests häufig lokal durchgeführt werden. Ich frage mich, ob es 10.000 Tests gibt, aber manchmal bekomme ich die Frage: "Oh, es gibt einige langsame Testfälle?" Noch problematischer ist es, wenn der Produktcode für das langsame Testen verantwortlich ist. Da das Test-Framework von Python pytest verwendet, ist es eine Erinnerung daran, dass im Fall von pytest unten nach einer langsamen Verarbeitung wie dieser gesucht wird.
Ich habe hauptsächlich die folgenden zwei Dinge getan.
① Geben Sie einen Testfall mit langer Verarbeitungszeit mit der Option "--durations" von pytest aus (2) Profil mit pytest-profiling, um langsame Verarbeitungspunkte zu identifizieren.
Dies ist der in diesem Artikel verwendete Testcode. Eine Liste von Ganzzahlen von 1 bis 10000000 in der Reihenfolge wird durch 4 Muster erstellt und schließlich durch Assert verglichen. Das Lesen des Ruhezustands in ** setup () ** ist nur enthalten, um das Verständnis bei der Ausgabe der Testverarbeitungszeit zu erleichtern, und ist für die Verarbeitung bedeutungslos.
Den Quellcode finden Sie unter hier.
test_sample.py
import time
import pytest
import sys
COUNT = 10000000
@pytest.fixture(scope='module')
def expected():
#Erstellen erwarteter Werte zum Vergleich mit assert
return [i for i in range(1, COUNT)]
@pytest.fixture(scope='function', autouse=True)
def setup():
#Hülse, die in Bezug auf die Verarbeitung bedeutungslos ist
time.sleep(0.1)
yield
time.sleep(0.2)
def test_1_1(expected):
actual = [i for i in range(1, COUNT)]
assert expected == actual
def test_1_2(expected):
actual = list({i for i in range(1, COUNT)})
assert expected == actual
def test_1_3(expected):
actual = []
for i in range(1, COUNT):
actual.append(i)
assert expected == actual
def test_1_4(expected):
actual = []
for i in range(1, COUNT):
# actual = actual + [i]Es braucht Zeit, um zu sterben
actual += [i]
assert expected == actual
Wenn Sie bei der Ausführung von pytest die Option "--durations = N" hinzufügen, wird der langsamste Test + N vor und nach der Verarbeitung (Setup / Teardown) im Ausführungsergebnis angezeigt. Wenn "N = 0" gesetzt ist, werden alle Ergebnisse ausgegeben.
Das Ergebnis der Ausführung von pytest mit "--durations = 0" ist wie folgt. Standardmäßig werden Ergebnisse von 0,01 s oder weniger ausgeblendet, aber mit der Option "-vv" werden alle Ergebnisse angezeigt.
=========== slowest test durations ===========
2.13s call tests/test_sample.py::test_1_3
1.25s call tests/test_sample.py::test_1_4
1.08s call tests/test_sample.py::test_1_2
0.81s call tests/test_sample.py::test_1_1
0.66s setup tests/test_sample.py::test_1_1
0.20s teardown tests/test_sample.py::test_1_2
0.20s teardown tests/test_sample.py::test_1_4
0.20s teardown tests/test_sample.py::test_1_3
0.20s teardown tests/test_sample.py::test_1_1
0.10s setup tests/test_sample.py::test_1_4
0.10s setup tests/test_sample.py::test_1_2
0.10s setup tests/test_sample.py::test_1_3
============= 4 passed in 7.40s =============
Die ersten vier sind die Ausführungsergebnisse von vier Testfällen. Es ist schnell in einfacher Einschlussnotation zu schreiben. Als nächstes dauert die Vorverarbeitung (Einrichtung) von ** test_1_1 () ** ungefähr 0,66 Sekunden. Dies scheint die Addition der Verarbeitungszeit von ** erwartet () ** + 0,1 Sekunden Schlaf in ** setup () ** zu sein. Darauf folgen vier Teardowns für jeden anderen Test- und Setup-Prozess als ** test_1_1 () **. Dies entspricht der in ** setup () ** beschriebenen Ruhezeit.
Nachdem Sie festgestellt haben, welche Tests langsam sind, müssen Sie feststellen, welche Prozesse im Test langsam sind, um die Geschwindigkeit zu verbessern. Laut Net Wisdom gibt es eine Möglichkeit, pytest und profiler gleichzeitig auszuführen. Es ist jedoch erforderlich, das Ausgabeergebnis des Profils separat unter Verwendung von ** pstats ** oder dergleichen zu analysieren. Als ich untersuchte, ob dieser Bereich leicht zu realisieren ist, kam ich zu pytest-profiling.
pytest-profiling
Sie können es mit pip installieren.
pip install pytest-profiling
Sie können das Profilergebnis auch als SVG ausgeben, aber Graphviz ist erforderlich. Installieren Sie es daher separat.
Es ist einfach zu bedienen, fügen Sie einfach die Option --profile-svg
hinzu, wenn Sie pytest ausführen.
pytest tests/test_sample.py --profile-svg
Bei Ausführung mit der Option --profile-svg
führt pytest-profiling die folgende Verarbeitung durch.
Wenn Sie "--profile" anstelle der Option "--profile-svg" hinzufügen, wird anscheinend der obige dritte Prozess ausgeführt.
Nach einer Reihe von Verarbeitungen wird ein Prof-Verzeichnis erstellt und eine Prof-Datei mit pstats-Analyseinformationen und ein SVG-Bild darunter erstellt. Die folgenden Dateien werden im prof-Verzeichnis erstellt.
prof
├ combined.prof
├ combined.svg
├ test_1_1.prof
├ test_1_2.prof
├ test_1_3.prof
└ test_1_4.prof
** test_1_1.prof ** bis ** test_1_4.prof ** sind Profilanalyseinformationen für jeden Testfall. Der Name des Tests wird dem Dateinamen zugewiesen, aber Japanisch usw. wird erstellt, indem er durch einen Unterstrich ersetzt wird. ** kombinierte.prof ** sind Informationen zur Profilanalyse für alle durchgeführten Tests. ** kombinierte.svg ** wird in ein Diagramm konvertiert und dann in ein SVG-Bild konvertiert, das wie das folgende Bild aussieht.
Das Lesen des Diagramms wird in der README-Datei von gprof2dot erläutert. Jeder Knoten des Diagramms enthält die folgenden Informationen.
+------------------------------+
| function name |
| total time % ( self time % ) |
| total calls |
+------------------------------+
Darüber hinaus werden die folgenden Informationen an der Kante beschrieben, die die aufrufende Funktion und die aufgerufene Funktion verbindet (ausgedrückt als Eltern und Kind).
total time %
calls
parent --------------------> children
Wenn Sie vom höchsten übergeordneten Knoten in absteigender Reihenfolge der Gesamtzeit% folgen, können Sie den langsam verarbeitenden Teil anscheinend leicht identifizieren.
Ich habe es zuerst unter Windows ausgeführt, aber die Prof-Datei wurde generiert, aber die SVG-Datei wurde nicht erstellt. Wenn Sie genau hinschauen, sieht es so aus, als ob Unterstütztes Betriebssystem Windows nicht enthält.
Da die Prof-Datei generiert wird, war es jedoch möglich, die Prof-Datei manuell in SVG zu konvertieren. Ich denke, gprof2dot wird installiert, wenn Sie pytest-profiling installieren.
gprof2dot -f pstats prof/combined.prof > prof/tmp
dot -Tsvg -o prof/combined.svg prof/tmp
Übrigens habe ich es über das Visual Studio Code-Terminal ausgeführt, aber beim Ausführen des Punktbefehls ist ein Fehler aufgetreten. Es scheint nicht zu funktionieren, wenn die Standard-Shell Powershell ist. Der Wechsel von "Select Default Shell" zu cmd hat gut funktioniert.
Wenn Sie Folgendes in die pytest-Konfigurationsdatei schreiben und im Stammverzeichnis des Projekts ablegen, wird die pytest-Profilerstellung ausgeführt, wenn pytest ausgeführt wird.
pytest.ini
[pytest]
testpaths = tests
python_files = test_*.py
addopts = -vv --durations=0 --profile-svg
pytest_plugins = ['pytest_profiling']
Wenn es jedoch viele Testfälle gibt, sind die Analyseinformationen kompliziert. Identifizieren Sie daher zuerst den langsamen Teil des Tests mit der Option "--durations" und führen Sie dann die Pytest-Profilerstellung nur für den entsprechenden Test durch, um den langsamen Teil des Prozesses zu identifizieren. Ich denke, es ist einfacher, es zu tun. Wenn Sie es in die Konfigurationsdatei schreiben, wird es jedes Mal ausgeführt.
Recommended Posts