it-swarm.dev

Wie schreibt man Unit-Testfälle?

Manchmal schreibe ich Unit-Testfälle für Code, den andere Entwickler geschrieben haben. Es gibt Fälle, in denen ich wirklich nicht weiß, was der Entwickler versucht (der geschäftliche Teil), und ich manipuliere einfach den Testfall, um die grüne Linie zu erhalten. Sind diese Dinge in der Branche normal?

Was ist der normale Trend? Sollen die Entwickler Unit-Testfälle für Code schreiben, den sie selbst geschrieben haben?

14

Versuchen Sie, diesen Blog-Beitrag zu lesen: Schreiben großartiger Unit-Tests: Beste und schlechteste Praktiken .

Aber es gibt unzählige andere im Web.

In direkter Antwort auf Ihre Fragen ...

  1. "Normaler Trend" - Ich denke, dies kann von Ort zu Ort unterschiedlich sein. Was für mich normal ist, kann für andere seltsam sein.
  2. Ich würde sagen (nach meiner Option), dass der Entwickler, der den Code schreibt, den Test schreiben sollte, idealerweise mit Methoden wie TDD, bei denen Sie den Test vor dem Code schreiben würden. Aber andere mögen hier andere Methoden und Ideen haben!

Und die Art und Weise, wie Sie das Schreiben der Tests (in Ihrer Frage) beschrieben haben, ist völlig falsch !!

12
user18041

Dieser Ansatz macht den Unit-Test wertlos.

Der Komponententest muss fehlschlagen, wenn eine echte Aktion nicht wie beabsichtigt funktioniert. Wenn Sie es nicht so machen und vielleicht sogar den Test vor dem zu testenden Code schreiben, ist es, als hätten Sie nicht funktionierende Rauchmelder.

9
user1249

In der realen Welt ist es völlig normal, Komponententests für den Code eines anderen zu schreiben. Sicher, der ursprüngliche Entwickler hätte dies bereits tun sollen, aber oft erhalten Sie Legacy-Code, bei dem dies einfach nicht getan wurde. Übrigens spielt es keine Rolle, ob dieser Legacy-Code vor Jahrzehnten aus einer weit entfernten Galaxie stammt oder ob einer Ihrer Mitarbeiter ihn letzte Woche überprüft hat oder ob Sie ihn heute geschrieben haben, Legacy-Code ist Code ohne Tests

Fragen Sie sich: Warum schreiben wir Unit-Tests? Going Green ist offensichtlich nur ein Mittel zum Zweck. Das ultimative Ziel ist es, Aussagen über den zu testenden Code zu beweisen oder zu widerlegen.

Angenommen, Sie haben eine Methode, mit der die Quadratwurzel einer Gleitkommazahl berechnet wird. In Java würde die Schnittstelle Folgendes definieren:

public double squareRoot(double number);

Es spielt keine Rolle, ob Sie die Implementierung geschrieben haben oder ob es jemand anderes getan hat, Sie möchten einige Eigenschaften von squareRoot behaupten:

  1. dass es einfache Wurzeln wie sqrt (4.0) zurückgeben kann
  2. dass es eine echte Wurzel wie sqrt (2.0) mit einer angemessenen Genauigkeit finden kann
  3. dass es feststellt, dass sqrt (0.0) 0.0 ist
  4. dass es eine IllegalArgumentException auslöst, wenn eine negative Zahl eingegeben wird, d. h. auf sqrt (-1.0)

Sie schreiben diese also als Einzeltests:

@Test
public void canFindSimpleRoot() {
  assertEquals(2, squareRoot(4), epsilon);
}

Ups, dieser Test schlägt bereits fehl:

Java.lang.AssertionError: Use assertEquals(expected, actual, delta) to compare floating-point numbers

Sie haben die Gleitkomma-Arithmetik vergessen. OK, Sie stellen double epsilon=0.01 und gehen:

@Test
public void canFindSimpleRootToEpsilonPrecision() {
  assertEquals(2, squareRoot(4), epsilon);
}

und füge die anderen Tests hinzu: endlich

@Test
@ExpectedException(IllegalArgumentException.class)
public void throwsExceptionOnNegativeInput() {
  assertEquals(-1, squareRoot(-1), epsilon);
}

und nochmal:

Java.lang.AssertionError: expected:<-1.0> but was:<NaN>

Sie sollten getestet haben:

@Test
public void returnsNaNOnNegativeInput() {
  assertEquals(Double.NaN, squareRoot(-1), epsilon);
}

Was haben wir hier gemacht? Wir begannen mit einigen Annahmen darüber, wie sich die Methode verhalten sollte, und stellten fest, dass nicht alle wahr waren. Wir haben dann die Testsuite Green erstellt, um den Beweis aufzuschreiben, dass sich die Methode gemäß unseren korrigierten Annahmen verhält. Jetzt können sich Clients dieses Codes auf dieses Verhalten verlassen. Wenn jemand die tatsächliche Implementierung von squareRoot gegen etwas anderes austauschen würde, was zum Beispiel wirklich eine Ausnahme auslöste, anstatt NaN zurückzugeben, würden unsere Tests dies sofort erkennen.

Dieses Beispiel ist trivial, aber oft erben Sie große Codeteile, bei denen unklar ist, was es tatsächlich tut. In diesem Fall ist es normal, ein Testkabel um den Code zu legen. Beginnen Sie mit ein paar grundlegenden Annahmen darüber, wie sich der Code verhalten soll, schreiben Sie Unit-Tests für sie, testen Sie. Wenn Grün, gut, schreibe mehr Tests. Wenn Rot, haben Sie jetzt eine fehlgeschlagene Behauptung, die Sie gegen eine Spezifikation halten können. Vielleicht gibt es einen Fehler im Legacy-Code. Möglicherweise ist die Spezifikation über diese bestimmte Eingabe unklar. Vielleicht haben Sie keine Spezifikation. Schreiben Sie in diesem Fall den Test so um, dass das unerwartete Verhalten dokumentiert wird:

@Test
public void throwsNoExceptionOnNegativeInput() {
  assertNotNull(squareRoot(-1)); // Shouldn't this fail?
}

Mit der Zeit erhalten Sie ein Testkabel, das dokumentiert, wie sich der Code tatsächlich verhält, und zu einer Art codierter Spezifikation wird. Wenn Sie den Legacy-Code jemals ändern oder durch einen anderen ersetzen möchten, können Sie anhand des Testkabels überprüfen, ob sich der neue Code gleich verhält oder ob sich der neue Code erwartungsgemäß und kontrolliert anders verhält (z. B. tatsächlich) behebt den Fehler, den Sie voraussichtlich beheben werden). Dieser Gurt muss am ersten Tag nicht vollständig sein. Tatsächlich ist es fast immer besser, einen unvollständigen Gurt zu haben, als überhaupt keinen Gurt zu haben. Wenn Sie ein Gurtzeug haben, können Sie Ihren Client-Code einfacher schreiben. Sie wissen, wo zu erwarten ist, dass Dinge kaputt gehen, wenn Sie etwas ändern, und wo sie kaputt gehen, wenn sie es schließlich tun.

Sie sollten versuchen, aus der Denkweise herauszukommen, dass Sie Komponententests schreiben müssen, nur weil Sie müssen, als würden Sie Pflichtfelder in einem Formular ausfüllen. Und Sie sollten keine Komponententests schreiben, nur um die rote Linie grün zu machen. Unit-Tests sind nicht deine Feinde, Unit-Tests sind deine Freunde.

3
wallenborn

Wenn Sie nicht wissen, was eine Funktion tut, können Sie keinen Komponententest dafür schreiben. Nach allem, was Sie wissen, macht es nicht einmal das, was es soll. Sie müssen zuerst herausfinden, was es tun soll. DANN schreibe den Test.

3
Edward Strange

Wenn ich Testfälle schreibe (für Drucker), versuche ich, an die einzelnen kleinen Komponenten zu denken ... und was kann ich tun, um sie möglicherweise zu beschädigen? Nehmen wir zum Beispiel den Scanner an, welche Befehle er verwendet (in der pjl-Druckerauftragssprache), was ich schreiben kann, um jede Funktionalität zu testen. Ok, was kann ich jetzt tun, um das zu unterbrechen?.

Ich versuche das für jede Hauptkomponente zu tun, aber wenn es um Software und nicht so viel Hardware geht, möchten Sie sich jede Methode/Funktion ansehen und Grenzen und dergleichen überprüfen.

1
user6791

Es hört sich so an, als würden Sie mit anderen Entwicklern zusammenarbeiten (oder Code pflegen, der von anderen Entwicklern geschrieben wurde), die keine Unit-Tests durchführen. In diesem Fall möchten Sie auf jeden Fall wissen, was das zu testende Objekt oder die zu testende Methode tun soll, und dann einen Test dafür erstellen.

Es wird kein TDD sein, weil Sie den Test nicht zuerst geschrieben haben, aber Sie könnten die Situation verbessern. Möglicherweise möchten Sie auch eine Kopie der zu testenden Objekte mit Stubs erstellen, damit festgestellt werden kann, dass Ihre Tests ordnungsgemäß funktionieren, wenn der Code fehlschlägt.

1
vjones