Warum nehmen so viele assertEquals()
oder ähnliche Funktionen den erwarteten Wert als ersten Parameter und den tatsächlichen als zweiten?
Dies scheint mir nicht intuitiv zu sein. Gibt es also einen besonderen Grund für diese ungewöhnliche Reihenfolge?
76
assertEqual
selbst an docs.python.org/2/library/… und das Durchsuchen dieser Seite zeigt, dass die Reihenfolge innerhalb des unittest-Moduls selbst inkonsistent ist. Aber dieses Python-Problem impliziert (tatsächlich, erwartet), dass es tatsächlich der Standard ist: bugs.python.org/issue10573assertEquals
veraltet ist - verwenden SieassertEqual
(obwohl zumindest in 2.7 nicht angegeben wird, welcher Parameter erwartet wird und welcher tatsächlich)self.assertEqual(ltuae, 42)
42 42 oder 54 erwartet wurde. Wenn ein Test fehlschlägt, soll die Meldung hilfreich und genau sein, damit der Fehler so schnell wie möglich behoben werden kann. Die neuen Parameternamen machen das schwieriger.Antworten:
Weil die Autoren eine 50% ige Chance hatten, Ihrer Intuition zu entsprechen.
Wegen der anderen Überlastung
Und die Erklärung, die Teil dessen ist, was Sie wissen, passt zum Erwarteten, was Sie wissen, im Gegensatz zu der tatsächlichen, die Sie zum Zeitpunkt des Schreibens des Codes nicht kennen.
quelle
assertGreater(a, b)
Behauptungb > a
intuitiv ist ... (und ich denke, deshalb haben sie die nicht kommutativen Methoden entfernt)=
anstelle einer Äquivalenzprüfung durchgeführt haben,==
da dies zu einem Fehler führen würde, wenn Sie versuchen, die Konstante neu zuzuweisen. (Ich glaube, ich habe es zum ersten Mal beim Schreiben von festem Code beworben gesehen.) Es erstellt (IMHO) weniger lesbaren Code (ich bevorzuge die Grammatik im Stil "Ergebnis sollte wie erwartet sein"), bringt den Compiler jedoch dazu, Ihre Chops zu sprengen, wenn Sie ein = weglassen ZeichenDie Antwort von Kent Beck , dem Erfinder von SUnit und JUnit (wo möglicherweise diese Konvention ihren Ursprung hat), lautet:
Dies ist jedoch so entgegengesetzt zu meiner eigenen Erfahrung, dass ich mich fragen muss, ob ich es falsch verstehe. Folgendes sehe ich oft in Tests:
assertEquals(12345, user.getId()); assertEquals("kent", user.getUsername()); assertEquals("Kent Beck", user.getName());
Ich würde denken, dass dies mit dem tatsächlichen Wert zuerst besser lesen würde . Dadurch wird mehr von der sich wiederholenden Boilerplate zusammengefügt und die Methodenaufrufe ausgerichtet, deren Werte wir testen:
assertEquals(user.getId(), 12345); assertEquals(user.getUsername(), "kent"); assertEquals(user.getName(), "Kent Beck");
(Und es gibt andere Gründe, warum ich diese Reihenfolge bevorzuge, aber für den Zweck dieser Frage, warum es anders ist, scheint Kents Argumentation die Antwort zu sein, auch wenn ich sie nicht verstanden habe.)
quelle
Ich stimme dem Konsens zu, dass Konsistenz die Nummer 1 ist, aber das Verhalten beim Vergleichen von Wörterbüchern kann ein hilfreicher Datenpunkt sein, wenn Sie diese Frage bewerten.
Wenn ich ein "+" auf einem Diff sehe, lese ich dies als "das getestete Verfahren hat dies hinzugefügt". Auch hier gelten persönliche Vorlieben.
Hinweis: Ich habe alphabetische Tasten verwendet und das Wörterbuch verlängert, sodass sich zur Verdeutlichung des Beispiels nur eine mittlere Taste ändert. Andere Szenarien zeigen mehr verschleierte Unterschiede. Bemerkenswert ist auch, dass assertEqual assertDictEqual in> = 2.7 und> = 3.1 verwendet
exl.py.
from unittest import TestCase class DictionaryTest(TestCase): def test_assert_order(self): self.assertEqual( { 'a_first_key': 'value', 'key_number_2': 'value', 'z_last_key': 'value', 'first_not_second': 'value', }, { 'a_first_key': 'value', 'key_number_2': 'value', 'z_last_key': 'value', 'second_not_first': 'value', } )
Ausgabe:
$ python -m unittest exl F ====================================================================== FAIL: test_assert_order (exl.DictionaryTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "exl.py", line 18, in test_assert_order 'second_not_first': 'value', AssertionError: {'a_first_key': 'value', 'z_last_key': 'value', 'key_number_2': 'value', 'first_ [truncated]... != {'a_first_key': 'value', 'z_last_key': 'value', 'key_number_2': 'value', 'second [truncated]... {'a_first_key': 'value', - 'first_not_second': 'value', 'key_number_2': 'value', + 'second_not_first': 'value', 'z_last_key': 'value'} ---------------------------------------------------------------------- Ran 1 test in 0.001s FAILED (failures=1)
quelle
Dies ist ein sehr spannendes Thema und auch hier viele sehr lehrreiche Antworten! Folgendes lerne ich von ihnen:
Intuitiv / kontraintuitiv kann als subjektiv angesehen werden. Unabhängig von der ursprünglich definierten Reihenfolge wären vielleicht 50% von uns nicht glücklich .
Persönlich hätte ich es vorgezogen, wenn es so konzipiert wäre
assertEqual(actual, expected)
, weil ich angesichts der konzeptionellen Ähnlichkeit zwischenassert
undif
wünschte, es würde zum Beispiel der Norm vonif actual == expect
if a == 1
folgen .(PS: Es ist wahr, dass es unterschiedliche Meinungen gibt, die dazu auffordern, eine if-Anweisung in "umgekehrter Reihenfolge" zu schreiben, dh
if(1==a) {...}
um Sie davor zu schützen, versehentlich eine zu verpassen=
. Aber dieser Stil war selbst im C / weit von der Norm entfernt C ++ Welt. Und wenn Sie zufällig Python-Code schreiben, sind Sie in erster Linie nicht anfällig für diesen bösen Tippfehler, da erif a = 1
in Python nicht gültig ist.)Der praktisch überzeugende Grund dafür
assertEqual(expect, actual)
ist, dass die unittest Bibliothek in Ihrer Sprache wahrscheinlich bereits dieser Reihenfolge folgt, um eine lesbare Fehlermeldung zu generieren. Zum Beispiel in Python, wenn Sie das tunassertEqual(expected_dictionary, actual_dictionary)
, wird Unittest mit dem Präfix fehlende Schlüssel in der tatsächlichen Anzeige-
und zusätzliche Tasten mit Präfix+
, wie wenn Sie ein tungit diff old_branch new_branch
.Intuitiv oder nicht, dies ist der überzeugendste Grund, sich an die
assertEqual(expected, actual)
Bestellung zu halten. Wenn Sie es nicht mögen, akzeptieren Sie es besser noch, denn "Praktikabilität schlägt Reinheit" .Wenn Sie eine Möglichkeit benötigen, sich an die Bestellung zu erinnern, wird diese Antwort
assertEqual(expected_result, actual_calculation)
mit der Reihenfolge der Zuweisungsanweisungen verglichenresult = calculate(...)
. Es kann ein guter Weg sein, sich das De-facto-Verhalten zu merken, aber meiner Meinung nach ist es nicht die unbestreitbare Begründung dieser Reihenfolge, die intuitiver ist.Also los geht's. Glücklich
assertEqual(expect, actual)
!quelle
Ein hintergründiger Zweck von
assertEqual()
ist es, Code für menschliche Leser zu demonstrieren. Da der einfachste Funktionsaufruf istresult = function(parameters)
, gewöhnt man sich daran, an den Rückgabewert links und den Aufruf rechts zu denken .Ein Test, der eine Funktion dokumentiert, zeigt also links ein Literal und rechts einen Aufruf.
assertEqual(15, sum((1,2,3,4,5)))
Das heißt (erwartet, tatsächlich). Ähnliches gilt für einen Ausdruck.
assertEqual(4, 2 + 2)
Wenn Sie gerne aneinanderreihen ( trotz PEP8 ), hilft der erwartete Parameter, links kürzer zu sein:
assertEqual(42, 2 * 3 * 7) assertEqual(42, (1 << 1) + (1 << 3) + (1 << 5)) assertEqual(42, int('110', int('110', 2)))
Vielen Dank an Andrew Weimholt und Ganesh Parameswaran für diese Formeln.
quelle
Die xUnit-Testkonvention wird erwartet / aktuell. Für viele ist das die natürliche Ordnung, denn das haben sie gelernt.
Interessanterweise gilt in einer Abweichung von der Konvention für ein xUnit-Framework qunit für tatsächlich / erwartet. Zumindest mit Javascript können Sie einfach eine neue Funktion erstellen, die die alte kapselt und ihr die ursprüngliche Variable zuweist:
quelle
Die Erklärung, die ich gehört habe, ist, dass es von TDD kommt.
In Test Driven Development beginnen Sie mit dem Test und schreiben dann den Code.
Das Starten von Behauptungen durch Schreiben der Erwartung und anschließendes Aufrufen des Codes, der sie erzeugen soll, ist eine Mini-Version dieser Denkweise.
Natürlich kann dies nur eine Geschichte sein, die die Leute erzählen. Ich weiß nicht, dass es ein bewusster Grund war.
quelle