3227 Stimmen

Wie teste ich eine Klasse, die private Methoden, Felder oder innere Klassen hat?

Wie kann ich mit JUnit eine Klasse testen, die interne private Methoden, Felder oder verschachtelte Klassen hat?

Es scheint schlecht, den Zugriffsmodifikator für eine Methode zu ändern, nur um einen Test durchführen zu können.

327 Stimmen

Der beste Weg, eine private Methode zu testen, ist, sie nicht direkt zu testen

30 Stimmen

3 Stimmen

Warum sollte eine private Funktion getestet werden? Sie wird ohnehin automatisch getestet (und muss getestet werden), wenn Sie die Funktion/Methode testen, die die private Funktion verwendet.

41voto

phareim Punkte 261

Beim Testen von Legacy-Code mit großen und eigenwilligen Klassen ist es oft sehr hilfreich, die eine private (oder öffentliche) Methode, die ich schreibe, testen zu können im Augenblick .

Ich benutze die junitx.util.PrivateAccessor -Paket für Java . Viele hilfreiche Einzeiler für den Zugriff auf private Methoden und private Felder.

import junitx.util.PrivateAccessor;

PrivateAccessor.setField(myObjectReference, "myCrucialButHardToReachPrivateField", myNewValue);
PrivateAccessor.invoke(myObjectReference, "privateMethodName", java.lang.Class[] parameterTypes, java.lang.Object[] args);

2 Stimmen

Stellen Sie sicher, dass Sie die gesamten JUnit-Addons ( sourceforge.net/projects/junit-addons ) Paket, nicht das von der Source Forge empfohlene Projekt PrivateAccessor.

2 Stimmen

Und stellen Sie sicher, dass Sie bei der Verwendung eines Class als ersten Parameter in diesen Methoden, dass Sie nur auf die static Mitglieder.

36voto

Grundlefleck Punkte 118989

Nach dem Ausprobieren von Cem Catikkas' Lösung durch Reflexion für Java, muss ich sagen, dass seine Lösung eleganter war, als ich sie hier beschrieben habe. Wenn Sie jedoch nach einer Alternative zur Verwendung von Reflection suchen und Zugriff auf den Quellcode haben, den Sie testen, ist dies immer noch eine Option.

Es kann sinnvoll sein, private Methoden einer Klasse zu testen, insbesondere bei testgetriebene Entwicklung Sie möchten kleine Tests entwerfen, bevor Sie einen Code schreiben.

Wenn Sie einen Test mit Zugriff auf private Mitglieder und Methoden erstellen, können Sie Bereiche des Codes testen, die nur mit Zugriff auf öffentliche Methoden schwer zu erfassen sind. Wenn eine öffentliche Methode mehrere Schritte umfasst, kann sie aus mehreren privaten Methoden bestehen, die dann einzeln getestet werden können.

Vorteile:

  • Kann bis zu einer feineren Granularität testen

Benachteiligungen:

  • Der Testcode muss sich in der gleichen Datei wie der Quellcode liegen, was die schwieriger zu pflegen ist
  • Ähnlich verhält es sich mit .class-Ausgabedateien: Sie müssen innerhalb desselben Pakets bleiben, das im Quellcode deklariert wurde.

Wenn jedoch kontinuierliche Tests diese Methode erfordern, kann dies ein Zeichen dafür sein, dass die privaten Methoden extrahiert werden sollten, die auf herkömmliche, öffentliche Weise getestet werden könnten.

Hier ein kompliziertes Beispiel, wie das funktionieren könnte:

// Import statements and package declarations

public class ClassToTest
{
    private int decrement(int toDecrement) {
        toDecrement--;
        return toDecrement;
    }

    // Constructor and the rest of the class

    public static class StaticInnerTest extends TestCase
    {
        public StaticInnerTest(){
            super();
        }

        public void testDecrement(){
            int number = 10;
            ClassToTest toTest= new ClassToTest();
            int decremented = toTest.decrement(number);
            assertEquals(9, decremented);
        }

        public static void main(String[] args) {
            junit.textui.TestRunner.run(StaticInnerTest.class);
        }
    }
}

Die innere Klasse würde kompiliert werden zu ClassToTest$StaticInnerTest .

Siehe auch: Java-Tipp 106: Statische innere Klassen für Spaß und Gewinn

30voto

Steve Chambers Punkte 33674

Bei Verwendung von Spring, ReflectionTestUtils bietet einige praktische Tools, die hier mit minimalem Aufwand weiterhelfen. Zum Beispiel, um ein Mock auf ein privates Mitglied einzurichten, ohne gezwungen zu sein, einen unerwünschten öffentlichen Setter hinzuzufügen:

ReflectionTestUtils.setField(theClass, "theUnsettableField", theMockObject);

30voto

TofuBeer Punkte 59410

Wie andere schon sagten: Testen Sie private Methoden nicht direkt. Hier sind ein paar Gedanken:

  1. Halten Sie alle Methoden klein und konzentriert (leicht zu testen, leicht zu finden, was falsch ist)
  2. Verwenden Sie Tools zur Codeabdeckung. Ich mag Cobertura (oh glücklicher Tag, es sieht so aus, als gäbe es eine neue Version!)

Führen Sie die Codeabdeckung für die Unit-Tests durch. Wenn Sie sehen, dass Methoden nicht vollständig getestet werden, fügen Sie den Tests etwas hinzu, um die Abdeckung zu erhöhen. Streben Sie eine Codeabdeckung von 100 % an, aber seien Sie sich bewusst, dass Sie das wahrscheinlich nicht erreichen werden.

0 Stimmen

Auf zur Codeabdeckung. Egal, welche Art von Logik sich in der privaten Methode befindet, Sie rufen diese Logik immer noch über eine öffentliche Methode auf. Ein Tool zur Codeabdeckung kann Ihnen zeigen, welche Teile durch den Test abgedeckt sind, so dass Sie sehen können, ob Ihre private Methode getestet wird.

2 Stimmen

Ich habe schon Klassen gesehen, bei denen die einzige öffentliche Methode main[] ist, und die dann eine grafische Benutzeroberfläche aufrufen und die Datenbank und einige Webserver weltweit verbinden. Es ist leicht zu sagen "nicht indirekt testen"...

29voto

Antony Booth Punkte 248

Private Methoden werden von öffentlichen Methoden konsumiert. Sonst sind sie toter Code. Deshalb testen Sie die öffentliche Methode, indem Sie die erwarteten Ergebnisse der öffentlichen Methode und damit der privaten Methoden, die sie verbraucht, überprüfen.

Das Testen privater Methoden sollte durch Debugging getestet werden, bevor Sie Ihre Unit-Tests für öffentliche Methoden ausführen.

Sie können auch mit Hilfe von testgetriebener Entwicklung debuggt werden, indem Sie Ihre Unit-Tests debuggen, bis alle Behauptungen erfüllt sind.

Ich persönlich glaube, dass es besser ist, Klassen mit TDD zu erstellen; Erstellen der öffentlichen Methode Stubs, dann erzeugen Unit-Tests mit alle die Behauptungen im Voraus definiert, so dass das erwartete Ergebnis der Methode feststeht, bevor Sie sie codieren. Auf diese Weise gehen Sie nicht den falschen Weg, indem Sie die Behauptungen der Einheitstests an die Ergebnisse anpassen. Ihre Klasse ist dann robust und erfüllt die Anforderungen, wenn alle Unit-Tests erfolgreich sind.

5 Stimmen

Dies ist zwar richtig, kann aber zu sehr komplizierten Tests führen - es ist besser, jeweils eine einzelne Methode zu testen (Unit-Testing), als eine ganze Gruppe von Methoden. Das ist kein schlechter Vorschlag, aber ich denke, es gibt hier bessere Lösungen - dies sollte der letzte Ausweg sein.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X