web-dev-qa-db-de.com

JUNIT testet ungültige Methoden

Ich habe eine Java-Klasse mit void-Methoden und möchte einen Unit-Test durchführen, um die maximale Code-Abdeckung zu erreichen.

Zum Beispiel habe ich diese Methode:

protected static void checkifValidElements(int arg1,  int arg2) {
    method1(arg1);
    method2(arg1);
    method3(arg1, arg2);
    method4(arg1, arg2);
    method5(arg1);
    method6(arg2);
    method7();
}

Es wurde aus einem Grund schlecht benannt, weil ich den Code zum besseren Verständnis übersetzt habe. Jede Methode überprüft, ob die Argumente gültig sind und gut geschrieben sind. 

Beispiel:

private static void method1(arg1) {
    if (arg1.indexOf("$") == -1) {

        //Add an error message 
        ErrorFile.errorMessages.add("There is a dollar sign in the specified parameter");
    }
}

Mein Unit-Test deckt die kleinen Methoden gut ab, weil ich sie frage, ob die ErrorFile-Datei die Fehlernachricht enthält, aber ich sehe nicht, wie ich meine Methode checkIfValidElements testen kann. Wenn ich die Codeabdeckung mit Maven ausführte, wird mir angezeigt, dass der Komponententest diesen Teil meiner Klasse abdeckt.

Die einzige Möglichkeit, die ich sehe, ist, diese Methode so zu ändern, dass ein Int oder Bollean-Wert wie folgt zurückgegeben wird:

protected static int checkifValidElements(int arg1,  int arg2) {
    method1(arg1);
    method2(arg1);
    method3(arg1, arg2);
    method4(arg1, arg2);
    method5(arg1);
    method6(arg2);
    method7();
    return 0;
}

Mit dieser Methode kann ich gleich behaupten, aber es scheint mir zwecklos, dies zu tun. Das Problem ist, dass ich ein paar Klassen habe, die so gestaltet sind und meinen Anteil an Unit-Tests senken. 

50
metraon

Ich möchte einen Unit-Test durchführen, um eine maximale Codeabdeckung zu erreichen

Die Codeabdeckung sollte niemals das Ziel von Unit-Tests sein. Sie sollten Komponententests schreiben, um zu beweisen, dass Ihr Code korrekt ist, oder helfen Sie Ihnen, ihn besser zu entwerfen, oder helfen Sie anderen, zu verstehen, was der Code tun soll.

aber ich sehe nicht, wie ich meine Methode checkIfValidElements testen kann, sie gibt nichts zurück oder ändert nichts. 

Nun, Sie sollten wahrscheinlich ein paar Tests durchführen, zwischen denen überprüft wird, ob alle 7 Methoden ordnungsgemäß aufgerufen werden - sowohl mit einem ungültigen als auch mit einem gültigen Argument, wobei jedes Mal die Ergebnisse von ErrorFile überprüft werden.

Angenommen, jemand hat den Anruf an folgende Adresse entfernt:

method4(arg1, arg2);

... oder versehentlich die Argumentreihenfolge geändert:

method4(arg2, arg1);

Wie würden Sie diese Probleme feststellen? Gehen Sie davon aus und entwerfen Sie Tests, um es zu beweisen.

54
Jon Skeet

Wenn Ihre Methode keine Nebenwirkungen hat und nichts zurückgibt, führt sie nichts aus. 

Wenn Ihre Methode einige Berechnungen durchführt und das Ergebnis dieser Berechnung zurückgibt, können Sie offensichtlich genug behaupten, dass das zurückgegebene Ergebnis korrekt ist.

Wenn Ihr Code nichts zurückgibt, aber Nebenwirkungen hat, können Sie den Code aufrufen und dann behaupten, dass die richtigen Nebenwirkungen aufgetreten sind. Welche Nebenwirkungen auftreten, bestimmt, wie Sie die Prüfungen durchführen.

In Ihrem Beispiel rufen Sie statische Methoden von Ihren nicht zurückkehrenden Funktionen auf. Dies macht es schwierig, es sei denn, Sie können überprüfen, ob das Ergebnis all dieser statischen Methoden korrekt ist. Ein besserer Weg - aus Testgesichtspunkten - besteht darin, tatsächliche Objekte einzufügen, in die Sie Methoden aufrufen. Sie können dann etwas wie EasyMock oder Mockito verwenden, um ein Mock-Objekt in Ihrem Unit-Test zu erstellen und das Mock-Objekt in die Klasse einzufügen. Mit dem Scheinobjekt können Sie dann behaupten, dass die richtigen Funktionen mit den richtigen Werten und in der richtigen Reihenfolge aufgerufen wurden.

Zum Beispiel:

private ErrorFile errorFile;

public void setErrorFile(ErrorFile errorFile) {
    this.errorFile = errorFile;
}

private void method1(arg1) {
    if (arg1.indexOf("$") == -1) {

        //Add an error message 
        errorFile.addErrorMessage("There is a dollar sign in the specified parameter");
    }
}

Dann können Sie in Ihrem Test schreiben:

public void testMethod1() {
    ErrorFile errorFile = EasyMock.createMock(ErrorFile.class);
    errorFile.addErrorMessage("There is a dollar sign in the specified parameter");
    EasyMock.expectLastCall(errorFile);
    EasyMock.replay(errorFile);

    ClassToTest classToTest = new ClassToTest();
    classToTest.setErrorFile(errorFile);
    classToTest.method1("a$b");

    EasyMock.verify(errorFile); // This will fail the test if the required addErrorMessage call didn't happen
}
18
Graham

Sie können immer noch eine ungültige Methode testen, indem Sie behaupten, dass sie die entsprechende Nebenwirkung hatte. In Ihrem method1-Beispiel könnte Ihr Gerätetest etwa so aussehen:

public void checkIfValidElementsWithDollarSign() {
    checkIfValidElement("$",19);
    assert ErrorFile.errorMessages.contains("There is a dollar sign in the specified parameter");
}
4
Jeff Storey

Ich denke, Sie sollten das Schreiben von Nebeneffektmethoden vermeiden. Geben Sie in Ihrer Methode true oder false zurück, und Sie können diese Methoden in Komponententests überprüfen.

2
Garbage

Sie können etwas lernen, das "Spott" genannt wird. Damit können Sie beispielsweise prüfen, ob: - Eine Funktion wurde aufgerufen - Eine Funktion wurde x-mal aufgerufen - Eine Funktion wurde mindestens x-mal aufgerufen - Eine Funktion wurde mit einem bestimmten Parametersatz aufgerufen. In Ihrem Fall können Sie beispielsweise anhand von Mocking prüfen, ob method3 einmal aufgerufen wurde, und zwar mit dem, was Sie als arg1 und arg2 übergeben.

Schauen Sie sich diese an: https://code.google.com/p/mockito/https://code.google.com/p/powermock/

2

Wenn Ihre Methode ungültig ist und Sie nach einer Ausnahme suchen möchten, können Sie expected: https://weblogs.Java.net/blog/johnsmart/archive/2009/09/27/testing-exceptions- verwenden. junit-47

1

Wenn dies in Ihrem Fall möglich ist, können Sie Ihre Methoden method1(arg1) ... method7() protected anstelle von private so einrichten, dass sie über die Testklasse im selben Paket zugänglich sind. Dann können Sie einfach alle diese Methoden separat testen.

0
martlin