Junit4: Nicht veraltete ExpectedException-Regel

Erstellt am 5. Mai 2019  ·  22Kommentare  ·  Quelle: junit-team/junit4

Nach dem Upgrade des Spring Frameworks auf JUnit 4.13 Beta 3 habe ich festgestellt, dass org.junit.rules.ExpectedException jetzt @Deprecated , und diese Änderung erzeugt viele Warnungen in einer großen Codebasis wie dieser.

Da 4.13 die letzte geplante Version in der 4.x-Reihe ist, halte ich es nicht für sinnvoll, eine so häufig verwendete und unterstützte Funktion abzulehnen.

Wenn Sie die Einstellung beibehalten, befürchte ich, dass dies nur Tausende (Millionen?) Entwickler ohne triftigen Grund verärgern wird.

rules

Hilfreichster Kommentar

@daicoden

Ich bin mir ziemlich sicher, dass assertThrows das Wurfobjekt zurückgibt, also könnten Sie es einfach erfassen und Behauptungen aufstellen, wie Sie es für jedes andere Objekt tun würden:

StatusRuntimeException thrown = assertThrows(StatusRuntimeException.class, () -> {
   GrpcDispatch.makeRequest(service::enableJob, JobReference.newBuilder().setName(UNKNOWN_JOB).build());
});

assertEquals(Status.INVALID_ARGUMENT, thrown.getStatus());

Alle 22 Kommentare

Ich denke, die Veraltungswarnung ist eine gute Möglichkeit, darauf hinzuweisen, dass etwas Besseres verfügbar ist, sodass die Warnungen nicht ohne triftigen Grund angezeigt werden. ExpectedException kann leicht missbraucht werden, wird aber dennoch vielerorts empfohlen.

Die Frage ist, wie problematisch es für unsere Benutzer ist, diese Warnungen zur Einstellung zu erhalten. In meinem Unternehmen werden zur Build-Zeit keine Warnungen zu veralteten Versionen angezeigt (nur beim Anzeigen von Code).

Ich denke, Sam hat hier Recht. Ich habe viele Builds gesehen, die alle (neuen) Compiler-Warnungen verbieten. Solche Projekte müssten alle ihre Testklassen durchlaufen, die ExpectedException und eine Anmerkung SuppressWarnings hinzufügen.

@stefanbirkner WDYT?

Es erscheint sinnvoll, dass Clients die Warnungen unterdrücken. Sie könnten auch alle Warnungen zu veralteten Versionen unterdrücken; Veraltete Warnungen als Fehler zu behandeln macht es unmöglich, etwas veraltet zu machen.

Die Einstellung ist unsere beste Möglichkeit, den Leuten zu zeigen, dass die alte API problematisch ist und viel bessere APIs verfügbar sind.

Mir ist bekannt, dass Entwickler Warnungen lokal innerhalb einer IDE unterdrücken können; Ich bin jedoch nicht der Meinung, dass es eine gute Idee ist, ein Kernfeature in der (geplanten) endgültigen Version von JUnit 4.x abzulehnen.

IMHO, es ist keine gute Idee, ein Kernfeature in der endgültigen Version eines Frameworks abzuschaffen, insbesondere nicht eines, das so weit verbreitet ist wie JUnit 4.

Als konkretes Beispiel haben wir in der Kerntestsuite von Spring Framework jetzt Tausende von veralteten Warnungen für die Verwendung der Regel ExpectedException .

Die einzigen Möglichkeiten die wir haben sind:

  1. Unterdrücken Sie Veraltungswarnungen in jeder einzelnen Testklasse, die ExpectedException .
  2. Verabschieden Sie sich von der Verwendung von ExpectedException in jeder einzelnen Testklasse, die es verwendet.
  3. Nichts tun.

Wenn wir mit # 1 gehen, können wir dies wahrscheinlich mit einigen Skripten erreichen, die Warnungen auf Klassenebene unterdrücken, aber dies würden dann veraltete Warnungen anderer APIs unterdrücken, über die wir wahrscheinlich Bescheid wissen wollen/müssen, und die wir nicht ignorieren. Andernfalls müssen wir jede Testklasse manuell durchgehen und jede Verwendung der ExpectedException API ablehnen, und das schließt jede einzelne Interaktion mit der Regelinstanz in allen betroffenen Testmethoden ein.

Wenn wir uns für # 2 entscheiden, ist dies ein großes Unterfangen, dessen manuelle Durchführung mehrere Tage dauern kann. Eine Teilautomatisierung ist möglich, aber die Investition in die Automatisierung (Scripting etc.) kann für sich genommen recht umfangreich sein.

Wenn wir uns für Nr. 3 entscheiden, haben wir (aus unserer Sicht) unnötige Warnungen vor der Einstellung, die unsere Sicht auf Warnungen über die Einstellung , die uns eigentlich wichtig sind, trüben, und das führt zu dem

Die zweite Vorgehensweise würde die zukünftige Migration auf JUnit 5 vereinfachen.

Die zweite Vorgehensweise würde die zukünftige Migration auf JUnit 5 vereinfachen.

Sicher. Das würde eine Migration zu JUnit Jupiter oder AssertJ potenziell einfacher machen; jedoch möchte oder muss nicht jeder vorhandene Testsuiten migrieren.

Daher halte ich das für kein stichhaltiges Argument.

Ich bin mir nicht sicher, warum dies wahrscheinlich die letzte Version von JUnit 4.x damit zusammenhängt, ob wir die Dinge veraltet oder nicht. JUnit löscht selten _beliebige_ APIs, daher war die Veraltung kein Hinweis darauf, dass eine API entfernt wird. Dies ist ein Hinweis darauf, dass die API möglicherweise nicht unterstützt wird und/oder bessere APIs vorhanden sind. Beides trifft in diesem Fall zu (wir haben vorgeschlagene Änderungen an dieser Regel abgelehnt, weil wir der Meinung sind, dass es besser ist, die Leute einfach assertThrows() ).

Ich schlage vor, Spring langsam weg von ExpectedException migrieren. Ein paar Tage Arbeit, die über mehrere Monate verteilt sind, um sicherere und leichter verständliche Tests zu erhalten, scheint ein Gewinn zu sein. Der Vorteil ist, dass andere Personen, die mit den jüngsten Änderungen an JUnit weniger vertraut sind, wissen, dass sie ExpectedException vermeiden können

ErrorProne hat eine Überprüfung dafür , die eine empfohlene Lösung bietet, daher glaube ich nicht, dass es mehrere Tage dauern würde, dieses Problem zu beheben.

TL;DR Ich bin dafür, ExpectedException abzulehnen.

@kcooney hat bereits gesagt, dass die

Ich denke, es ist hilfreich, die Einstellung zu verwenden, da sie den Leuten sagt, dass es eine bessere Möglichkeit gibt, Ausnahmen zu überprüfen. Ich habe in den letzten 10 Jahren für einige Unternehmen gearbeitet und es gibt immer Leute, die überrascht sind, dass es etwas Besseres als @Test(expected=ABeautifulException.class . Deprecation ist für sie wertvoll, da sie normalerweise einen Blick darauf werfen, wenn sie Code sehen, der in der IDE durchgestrichen ist.

Die Warnungen zur Veraltung können ärgerlich sein, da diese Warnungen nicht korrigiert werden müssen. Der Ursprung dafür liegt in der Art und Weise, wie JUnit 4 die Deprecation verwendet. Daher denke ich, dass es dafür keine Lösung gibt, abgesehen davon, dass ExpectedException nicht veraltet ist (und schließlich überhaupt keine veraltet).

Nicht zuletzt gibt es Unternehmen, deren Builds bei Veraltungswarnungen kaputt gehen und sie daher nicht ohne weiteres auf JUnit 4.13 aktualisieren können. Ich bin mir nicht sicher, wie viele dieser Unternehmen existieren, die a) diese Build-Richtlinie haben und b) auf JUnit 4.13 aktualisieren möchten.

@sdeleuze , @mp911de und @rweisleder Sie haben dafür gestimmt , die Einstellung rückgängig zu machen. Es wäre hilfreich, wenn Sie uns mitteilen, warum es nicht eingestellt werden soll.

Nur für ein bisschen mehr Informationen, es dauerte etwa 1,5 Tage Spring Framework des Code - Basis von JUnit zu migrieren ExpectedException zu AssertJ des assertThatExceptionOfType .

Ein kleiner Vorschlag, der hilfreich sein könnte, besteht darin, nur die Methode ExpectedException.none() und nicht die gesamte Klasse als veraltet zu betrachten. Dies würde die Leute immer noch warnen, aber es würde es viel einfacher machen, isoliert zu unterdrücken.

ExpectedException JUnit wird als primitiver Typ in Tests verwendet, die umfangreichere Ausnahmezusicherungen durchführen als nur @Test(expected = …) . Dies sind normalerweise Tests, die auf Hamcrest oder integrierten Assertionen basieren und nicht so sehr auf AssertJ oder ähnliches.

JUnit 4.13 zu haben ist ein Signal für aktive Wartung. Codebasen, die auf der JUnit 4.x-API verbleiben, werden wahrscheinlich nicht bald auf die JUnit 5-API migriert, sondern behalten die API bei, wobei möglicherweise auf die Vintage-Engine migriert wird. Eine plötzlich veraltete Klasse erzeugte neue Warnungen und zusätzlichen Aufwand, um zu einem anderen Assertion-Dienstprogramm zu migrieren, obwohl der Code möglicherweise noch funktioniert.

Ich habe einige Male die Einstellung und Einführung einer verbesserten API beobachtet. In den meisten Fällen half die Einstellung den Betreuern und nicht den tatsächlichen Benutzern. Auf Anwenderseite erzeugte dies meist Aufwand ohne Nutzen.

Ein kleiner Vorschlag, der hilfreich sein könnte, besteht darin, nur die Methode ExpectedException.none() und nicht die gesamte Klasse als veraltet zu betrachten. Dies würde die Leute immer noch warnen, aber es würde es viel einfacher machen, isoliert zu unterdrücken.

Wenn das JUnit 4-Team beschließt, die ExpectedException Regel nicht zu missbilligen, wäre dies meiner Meinung nach ein guter Kompromiss.

Ich frage mich, ob @Test(expected = ...) auch veraltet sein sollte, da wir jetzt assertThrows . Oder zumindest sollte der Verweis auf ExpectedException aus dem Javadoc des Attributs entfernt werden.

Ich frage mich, ob @Test(expected = ...) auch veraltet sein sollte, da wir jetzt assertThrows . Oder zumindest sollte der Verweis auf ExpectedException aus dem Javadoc des Attributs entfernt werden.

Ja, das expected Attribut in org.junit.Test sollte wahrscheinlich veraltet sein. In jedem Fall sollte das Javadoc auf Klassenebene für org.junit.Test und das Attribut expected aktualisiert werden, um die Verwendung von assertThrows zu empfehlen.

Ich wäre dafür, nur ExpectedException.none() .

Ich glaube, dass die Verwendung von Deprecation zum Bewerben einer neuen Funktion ein schwerfälliger Ansatz ist, der das Vertrauen in den JUnit-Entwicklungsprozess beschädigen und die Einführung von Version 4.13 behindern würde.

Es sollte eine Versionsüberschneidung geben, wenn das alte und das neue Feature nebeneinander existieren, ohne dass eines der beiden veraltet ist. Wie andere darauf hingewiesen haben, sind Abhängigkeiten von veralteten Methoden für viele Projekte, die die Codequalität hoch halten, ein No-Go. Das bedeutet, dass das JUnit-Upgrade im selben Commit erfolgen sollte wie die Änderungen, um die gesamte Codebasis zu migrieren.

Ich glaube, die einzige Situation, in der ein Feature veraltet ist und der Ersatz in derselben Version hinzugefügt wird, ist, wenn das Feature grundlegend defekt ist und sofort migriert werden sollte. Ich glaube nicht, dass ExpectedException grundlegend kaputt ist.

Ich würde oft neuere Abhängigkeiten überprüfen, um zu sehen, welche Änderungen kommen und wie ich meinen Code vorbereiten kann. Wie bereite ich meinen Code für die JUnit 4.13-Migration vor? Ich weiß, dass ExpectedException wird, aber ich habe noch keinen guten Ersatz. Ich müsste meinen eigenen Code implementieren, um Ausnahmen abzufangen und zu überprüfen, um dieses Durcheinander vollständig zu vermeiden.

Nur weil 4.13 als letztes 4.x-Release geplant ist, ist dies kein guter Grund, vernünftige Softwareentwicklungspraktiken aufzugeben. Tatsächlich kann 4.13 ohne die ExpectedException Deprecation veröffentlicht werden und 4.14 kann am nächsten Tag mit der Deprecation veröffentlicht werden. Das würde die Botschaft vermitteln und den Entwicklern eine kleine Verschnaufpause geben, um die Migration ohne übermäßigen Druck durchzuführen.

Es sollte eine Versionsüberschneidung geben, wenn das alte und das neue Feature nebeneinander existieren, ohne dass eines der beiden veraltet ist.

Wieso den? Die Absicht der Einstellung besteht darin, die Leute auf die neue, unserer Meinung nach bessere API aufmerksam zu machen.

Ich stimme auch zu, dass wir ExpectedException.none() nur ablehnen sollten, um es weniger invasiv zu machen.

@stefanbirkner Ok bei dir?

@marcphilipp Wenn ich meinen Code aktualisiere, möchte ich, dass die Dinge ohne ExpectedException in der nächsten Version veraltet sein wird und einen Ersatz vorschlagen. Auf diese Weise kann ich meinen Code Schritt für Schritt migrieren, ohne in der Zwischenzeit Einstellungen zulassen zu müssen. Das ist nur eine einfache Höflichkeit gegenüber den Benutzern, die JUnit 4.12 seit Jahren verwenden und keine großen Änderungen wünschen.

IMHO ist der Sinn einer Veraltungswarnung _ist_, um Ihnen Zeit zu geben, Ihren Code in Richtung des Ersatzes zu migrieren. Wenn Sie die Veraltungswarnung umgehen müssen, können Sie Ihre eigene temporäre Factory-Methode erstellen, die an ExpectedException.none() delegiert.

OK, die PR mildert das Problem bis zu einem gewissen Grad, es ist definitiv ein Schritt in die richtige Richtung. Danke, dass Sie das tun!

Anstatt vorzuschlagen, dass Benutzer eine Factory-Methode implementieren, könnte der Code eine eigene, nicht veraltete Methode bereitstellen (vielleicht none mit einem zusätzlichen Argument).

Ich verstehe immer noch nicht den Widerstand, den Nutzern eine Übergangsversion zu geben. Beim Implementieren einer inkompatiblen Änderung ist es sehr üblich, eine Version zu erstellen, die einen Übergang ermöglicht, ohne ihn in irgendeiner Weise zu erzwingen.

Ohne eine Übergangsversion würden Benutzer 4.13 ausprobieren, jede Menge Warnungen sehen und zu 4.12 zurückkehren.

Mit einer Übergangsversion würden Benutzer 4.14 ausprobieren, Tonnen von Warnungen sehen, 4.13 ausprobieren, keine Warnungen sehen, es verwenden. Einige würden schnell auf 4.14 aktualisieren, andere würden gerne bei 4.13 bleiben, es sei denn, sie haben einen guten Grund für ein Update. Es sollte so oder so gut sein.

Ich verstehe auch nicht, warum diese Einstellung in JUnit 4 passieren sollte. Ich migriere zu JUnit 5 mit dem junit-vintage-engine , um beide Versionen vorübergehend zu unterstützen. Aber dies zieht JUnit 4.13, das aus irgendeinem Grund entschieden hat, dass es eine gute Idee war, Dinge (die seit Jahren unterstützt wurden) in einer seiner wahrscheinlich letzten Veröffentlichungen zu verwerfen.

Es scheint auch keinen anderen Grund für die Einstellung zu geben, als auf eine Alternative hinzuweisen - dies hätte zumindest durch das Anbieten einer Alternative erreicht werden können (den Konstruktor öffentlich machen oder eine andere statische Methode anbieten - Nachricht kommuniziert).

Der ExpectedException Code, wie er jetzt ist, wird weiterhin funktionieren (und auch in späteren Versionen funktionieren), da er einfach die grundlegenden Funktionen von JUnit verwendet, die (damals) bequem angeboten werden.

Was ist der Ersatz für das Zuweisen von Eigenschaften über die Ausnahme...

alter Code:

thrown.expect(StatusRuntimeException.class);
thrown.expect(its(StatusRuntimeException::getStatus, toBe(Status.INVALID_ARGUMENT)));
GrpcDispatch.makeRequest(service::enableJob, JobReference.newBuilder().setName(UNKNOWN_JOB).build());

Scheint, als ob assertThrows eine Matcher-Version fehlt, damit die erwartete Ausnahme vollständig veraltet ist .... Ich weiß, dass es zu spät ist, aber sonst hat niemand dieses Problem?

@daicoden

Ich bin mir ziemlich sicher, dass assertThrows das Wurfobjekt zurückgibt, also könnten Sie es einfach erfassen und Behauptungen aufstellen, wie Sie es für jedes andere Objekt tun würden:

StatusRuntimeException thrown = assertThrows(StatusRuntimeException.class, () -> {
   GrpcDispatch.makeRequest(service::enableJob, JobReference.newBuilder().setName(UNKNOWN_JOB).build());
});

assertEquals(Status.INVALID_ARGUMENT, thrown.getStatus());
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen