Ist es eine gute Idee, die Leistung einer Methode mithilfe des Zeitlimits für Einheitentests zu messen?

14

In einem Projekt mit nichtfunktionalen Anforderungen, in denen die maximale Ausführungszeit für eine bestimmte Aktion festgelegt ist, muss die Qualitätssicherung die Leistung dieser Aktion auf einer dedizierten Maschine unter Verwendung präziser Hardware unter genauer Last überprüfen, wobei sowohl die Hardware als auch die Last in den Anforderungen angegeben sind.

Andererseits können einige fehlerhafte Änderungen am Quellcode die Leistung erheblich beeinträchtigen. Das frühzeitige Erkennen dieser negativen Auswirkungen , bevor der Quellcode die Quellcodeverwaltung erreicht und von der QA-Abteilung überprüft wird, kann sich positiv auf den Zeitverlust auswirken , den die QA-Abteilung, die das Problem meldet, und der Entwickler, der es mehrere Male später behebt, auswirken .

Ist es eine gute Idee, dies zu tun:

  • Unit-Tests verwenden, um eine Vorstellung von der Zeit zu erhalten, die für die n- fache Ausführung derselben Aktion aufgewendet wurde.

  • So verwenden Sie das Zeitlimit pro Test über das [TestMethod, Timeout(200)]Attribut in C #

Ich erwarte einige Probleme mit diesem Ansatz:

  • Konzeptionell sind Unit-Tests nicht wirklich dafür: Sie sollen einen kleinen Teil eines Codes testen, nicht mehr: weder die Überprüfung einer Funktionsanforderung, noch einen Integrationstest oder einen Leistungstest.

  • Misst das Zeitlimit für Komponententests in Visual Studio wirklich, was gemessen werden soll, wobei zu berücksichtigen ist, dass Initialisierung und Bereinigung für diese Tests nicht vorhanden sind oder zu kurz sind, um die Ergebnisse zu beeinflussen?

  • Das Messen der Leistung auf diese Weise ist hässlich. Das Ausführen eines Benchmarks auf einem beliebigen Computer¹ unabhängig von Hardware, Last usw. entspricht einem Benchmark , der zeigt, dass ein Datenbankprodukt immer schneller ist als ein anderes. Andererseits erwarte ich nicht, dass diese Unit-Tests ein definitives Ergebnis sind oder von der QS-Abteilung verwendet werden . Diese Komponententests dienen lediglich dazu, eine allgemeine Vorstellung von der erwarteten Leistung zu vermitteln und den Entwickler darauf aufmerksam zu machen, dass bei seiner letzten Änderung etwas kaputt gegangen ist, was die Leistung erheblich beeinträchtigt .

  • Test Driven Development (TDD) ist für diese Tests nicht möglich. Wie würde es an erster Stelle scheitern, bevor mit der Implementierung von Code begonnen wird?

  • Zu viele Leistungstests wirken sich auf die Zeit aus, die zum Ausführen der Tests erforderlich ist. Daher ist dieser Ansatz nur auf kurze Aktionen beschränkt.

Angesichts dieser Probleme finde ich es immer noch interessant, solche Komponententests zu verwenden, wenn sie mit den tatsächlichen Leistungskennzahlen der QA-Abteilung kombiniert werden.

Liege ich falsch? Gibt es noch andere Probleme, die die Verwendung von Komponententests für diesen Zweck völlig inakzeptabel machen?

Wenn ich mich irre, wie kann ich den Entwickler auf eine Änderung des Quellcodes aufmerksam machen, die die Leistung erheblich beeinträchtigt, bevor der Quellcode die Quellcodeverwaltung erreicht und von der QA-Abteilung überprüft wird?


¹ Tatsächlich wird erwartet, dass die Komponententests nur auf Entwickler-PCs mit vergleichbarer Hardwareleistung ausgeführt werden. Dies verringert die Lücke zwischen den schnellsten Computern, die den Leistungstest niemals bestehen werden, und den langsamsten Computern, die ihn niemals bestehen werden.

² Mit Aktion meine ich ein ziemlich kurzes Stück Code, dessen Ausführung einige Millisekunden in Anspruch nimmt.

Arseni Mourzenko
quelle

Antworten:

3

Wir verwenden auch diesen Ansatz, dh wir haben Tests, die die Laufzeit unter einem definierten Lastszenario auf einer bestimmten Maschine messen. Es kann wichtig sein, darauf hinzuweisen, dass wir diese nicht in die normalen Komponententests einbeziehen. Unit-Tests werden grundsätzlich von jedem Entwickler auf einem Entwicklercomputer ausgeführt, bevor die Änderungen übernommen werden. Lesen Sie weiter unten, warum dies für Leistungstests keinen Sinn ergibt (zumindest in unserem Fall). Stattdessen führen wir Leistungstests im Rahmen von Integrationstests durch.

Sie haben richtig darauf hingewiesen, dass dies eine Überprüfung nicht ausschließen sollte. Wir gehen nicht davon aus, dass unser Test ein Test für die nicht funktionierende Anforderung ist. Stattdessen betrachten wir es als bloßen potenziellen Problemindikator.

Ich bin mir über Ihr Produkt nicht sicher, aber in unserem Fall bedeutet eine unzureichende Leistung, dass viel Arbeit erforderlich ist, um dies zu beheben. Die Bearbeitungszeit, in der wir dies vollständig der Qualitätssicherung überlassen, ist schrecklich. Darüber hinaus haben die Leistungskorrekturen schwerwiegende Auswirkungen auf einen großen Teil der Codebasis, wodurch frühere QA-Arbeiten ungültig werden. Alles in allem ein sehr ineffizienter und unbefriedigender Workflow.

Abgesehen davon, hier sind einige Punkte zu Ihren jeweiligen Problemen:

  • konzeptionell: Es ist wahr, dass dies nicht das ist, worum es bei Unit-Tests geht. Aber solange jeder weiß, dass der Test nichts bestätigen soll, was die Qualitätssicherung tun soll, ist das in Ordnung.

  • Visual Studio: dazu kann ich nichts sagen, da wir das Unit-Test-Framework von VS nicht verwenden.

  • Maschine: Abhängig vom Produkt. Wenn Ihr Produkt für Endbenutzer mit benutzerdefinierten individuellen Desktop-Computern entwickelt wurde, ist es in der Tat realistischer, die Tests auf Computern verschiedener Entwickler durchzuführen. In unserem Fall liefern wir das Produkt für eine Maschine mit einer bestimmten Spezifikation und führen diese Leistungstests nur auf einer solchen Maschine durch. In der Tat macht es nicht viel Sinn, die Leistung auf Ihrem Dual-Core-Entwicklercomputer zu messen, wenn der Client letztendlich 16 Kerne oder mehr ausführt.

  • TDD: Während der anfängliche Ausfall typisch ist, ist er kein Muss. In der Tat dient das frühe Schreiben dieser Tests eher als Regressionstest als als traditioneller Komponententest. Dass der Test frühzeitig erfolgreich ist, ist kein Problem. Sie haben jedoch den Vorteil, dass dieser TDD-Test dies erkennt, wenn ein Entwickler Funktionen hinzufügt, die die Leistung verlangsamen, da ihm die nicht funktionierenden Leistungsanforderungen nicht bekannt waren. Passiert sehr oft und es ist ein großartiges Feedback. Stellen Sie sich vor, dass Sie in Ihrer täglichen Arbeit Code schreiben, ihn festschreiben, zum Mittagessen gehen und wenn Sie zurück sind, das Build-System Ihnen mitteilt, dass dieser Code bei Ausführung in einer Umgebung mit hoher Last zu langsam ist. Das ist schön genug für mich zu akzeptieren, dass der TDD-Test zunächst nicht fehlgeschlagen ist.

  • Laufzeit: Wie bereits erwähnt, führen wir diese Tests nicht auf Entwicklermaschinen aus, sondern als Teil des Build-Systems in einer Art Integrationstest.

Frank
quelle
3

Ich stimme größtenteils mit Ihrem Denken überein. Einfach meine Argumentation mit unabhängigem Fluss aufstellen.

1.
Lassen Sie es funktionieren, bevor Sie es verbessern / beschleunigen Bevor der Code eine Leistungsmaßnahme liefert (geschweige denn garantiert), sollte er zuerst korrigiert werden, dh funktionsfähig gemacht werden. Das Optimieren von Code, der funktional falsch ist, ist nicht nur Zeitverschwendung, sondern behindert auch die Entwicklung.

2. Leistung eines Systems nur bei vollem System
sinnvoll In der Regel hängt jede sinnvolle Leistung immer von einer bestimmten Infrastruktur ab und sollte nur bei vollem System gesehen werden. Beispiel: Wenn das Modul während des Mock-Tests Antworten aus lokalen Textdateien erhält, diese jedoch in der Produktionsumgebung aus der Datenbank abgerufen werden, ist dies früher der Fall

3. Die Leistungsskalierung sollte nach Ziel erfolgen.
Sobald Sie über das funktionierende System verfügen, müssen Sie die Leistung des Systems analysieren und Engpässe finden, um zu verstehen, wo Sie die Leistung skalieren müssen. Der blinde Versuch, jede Methode zu optimieren, bevor Sie wissen, dass die Leistung eines vollständigen Systems nicht ausreicht, kann zu unnötigem Arbeitsaufwand führen (Optimieren von Methoden, die keine Rolle spielen) und dazu, dass der Code unnötig aufgebläht wird.

Ich bin mir der Funktionalität von Visual Studio nicht ganz bewusst, aber im Allgemeinen benötigen Sie ein umfassenderes Profilerstellungs-Tool.

Dipan Mehta
quelle
2

Ich hatte vor einiger Zeit eine ähnliche Aufgabe und die endgültige Lösung befand sich irgendwo in der Mitte zwischen Komponententests und vollständig automatisierten Leistungstests.

Einige Überlegungen in keiner bestimmten Reihenfolge, die nützlich sein können:

  • Das Testen der Leistung durch die Qualitätssicherung war arbeitsintensiv und hatte einen eigenen Zeitplan (z. B. einmal in der Iteration). Daher war es kein Problem, die Quellcodeverwaltung zu aktivieren.
  • Unser System war groß und modular, Komponententests waren zu detailliert für unsere Anforderungen und wir haben spezielle "Fett" -Komponententests erstellt, die sorgfältig ausgearbeitet wurden, um Leistungsprobleme in den spezifischen Bereichen des Interesses auszulösen (sie wurden ebenfalls kategorisiert, aber dies ist der Fall) ein Implementierungsdetail).
  • Es gelten weiterhin die üblichen Einschränkungen für Komponententests: Sie sollten klein, schnell und präzise sein.
  • Um den Einfluss von Testframeworks auszuschließen, wurden sie von einem speziellen Wrapper ausgeführt, sodass wir genau wussten , wie viel Zeit die jeweilige Operation in Anspruch nimmt.
  • Es ist möglich, sie zu schreiben, bevor die eigentliche Implementierung abgeschlossen ist (Ergebnisse können je nach Prozess irrelevant oder nützlich sein, möglicherweise experimentieren die Entwickler noch mit der Implementierung und möchten sehen, wie sie insgesamt abläuft).
  • Sie wurden nach jedem Build vom CI-Server ausgeführt , daher sollte die Gesamtlaufzeit relativ kurz gehalten werden (wenn dies nicht der Fall ist, wird es erheblich schwieriger, die genaue Änderung zu bestimmen, die das Problem ausgelöst hat).
  • Der CI-Server war leistungsstark und die Hardware wurde repariert. Wir haben ihn als dedizierten Computer gezählt (es ist möglich, einen wirklich dedizierten Server mithilfe eines Remote-Build-Agenten zu verwenden).
  • Der Test-Wrapper sammelte alle relevanten Informationen (Hardwarespezifikationen, Testnamen / -kategorien, Systemlast, verstrichene Zeit usw.) und exportierte sie als Berichte oder in die Datenbank.
  • Wir haben ein Gadget für JIRA, das diese Berichte abruft und nette Diagramme nach Name / Kategorie / Build-Nummer mit einigen Steuerelementen zeichnet (vorherige Version auf die aktuelle Version übertragen usw.), damit die Entwickler ihre Auswirkungen schnell erkennen und Manager einen Überblick erhalten können (einige rot, alle grün, weißt du, es ist wichtig für sie).
  • Anhand der gesammelten Statistiken konnte der zeitliche Verlauf des Projekts analysiert werden.

Letztendlich hatten wir also ein skalierbares, flexibles und vorhersehbares System, das wir schnell auf unsere speziellen Anforderungen abstimmen können. Die Implementierung erforderte jedoch einige Anstrengungen.

Zurück zu den Fragen. Konzeptionelle Unit-Tests sind nicht dazu gedacht, aber Sie können die Funktionen Ihres Test-Frameworks nutzen. Ich habe Test-Timeouts nie als Mittel zur Messung angesehen, es ist nur ein Sicherheitsnetz für Hänge und dergleichen. Aber wenn Ihr aktueller Ansatz für Sie funktioniert, dann nutzen Sie ihn weiterhin, seien Sie praktisch. Sie können sich später immer noch etwas einfallen lassen, wenn es nötig ist.

Oleg Kolosov
quelle
0

Ich denke, es geht dir gut. Dies ist genau der Punkt, an dem es zu Zeitüberschreitungen beim Unit-Test kommt: um zu überprüfen, ob etwas viel länger dauert , als es sollte. Es gibt Einschränkungen für diesen Ansatz, aber Sie scheinen sich dessen bereits bewusst zu sein. Solange Sie diese Einschränkungen berücksichtigen, sehe ich kein Problem.

Mike Baranczak
quelle