Namenskonvention für Testpakete

11

Wir benennen unsere Testpakete genau wie ihre zu testenden Gegenstücke. Am Ende haben wir also diese Struktur:

src/main/java
    com.hello.world
        helloWorld.java
src/test/java
    com.hello.world
        helloWorldTest.java

Ich hatte immer das Gefühl, dass dies nicht besonders klug ist, da man nicht zwischen "test" und "to-test" unterscheiden kann, wenn man nur den Paketnamen angibt. Andererseits habe ich keinen Fall gefunden, in dem das irgendwie wichtig ist. Ist es eine gute Praxis, für beide Pakete (für die Testfälle und die Quellklassen) die gleichen Namenskonventionen zu haben? Wenn nicht, was wäre ein besserer Ansatz?

OddDev
quelle
1
Keine Ahnung, ob es eine gute Praxis ist, aber es ist eine beliebte. Die andere Option (um "Test" in den Paketnamen, Methodennamen usw. einzufügen) riecht etwas zu viel nach "Schlumpfbenennung". Wie Sie sagen, ist es schwer vorstellbar, dass es ein Problem wäre, nicht zwischen "Test" und "Test" zu unterscheiden, wenn nur der Paketname angegeben würde.
David Arno
@DavidArno Danke für deine Eingabe :) Wie vermeide ich dann Schlumpfnamen? Ich meine, wir würden am Ende mit com.hello.world.test.helloWorld.java enden, nicht wahr?
OddDev
Das "Schlumpf" -Problem ist mehr, wenn Sie eine Methode XXXTest()in haben com.hello.world.test.helloWorldTest.java. Allgemeiner Rat wäre, "Test" nur einmal im Pfad erscheinen zu lassen. Verwenden Sie also entweder (a) Test im Paketnamen (und benennen Sie die Testdatei genauso wie die zu testende Datei) oder (b) machen Sie den Paketnamen zum gleich und füge "test" zum Datei- / Klassennamen hinzu.
David Arno
@ DavidArno Ah, danke für die Klarstellung! Ich habe deinen ersten Kommentar falsch verstanden. Ich hab es jetzt.
OddDev
Nun würde ich argumentieren , dass, wenn es unklar ist, ich bekam meinen ersten Kommentar falsch :)
David Arno

Antworten:

11

Das ist eine gute Konvention.

Manchmal möchten Sie auch Komponententests für paketprivate Klassen und Methoden schreiben. Sie können sie nicht aus einer Unit-Test-Klasse aufrufen, die in einem anderen Paket enthalten ist.

Es sollte keine Verwirrung darüber geben, dass sich Unit-Test-Klassen im selben Namespace befinden, wie sie sich beim Kompilieren oder Ausführen des Produktionscodes nicht im Klassenpfad befinden sollten.

Hier ist ein Beispiel für ein kleines Modul mit einer öffentlichen Schnittstelle, einer öffentlichen Factory-Klasse und zwei paketprivaten Implementierungsklassen:

src/main/java:
    com.hello.transmogrifier
        public interface Transmogrifier
        public class TransmogrifierFactory
        class MapTransmogrifier implements Transmogrifier
        class ListTransmogrifier implements Transmogrifier

scr/test/java:
    com.hello.transmogrifier
        public class TransmogrifierFactoryTest
        public class MapTransmogrifierTest
        public class ListTransmogrifierTest

Das Ausblenden der Implementierungen der Transmogrifier-Schnittstelle könnte eine gültige Entwurfsentscheidung sein. Vielleicht liegt es in der Verantwortung der Factory-Klasse, die Implementierung auszuwählen.

Da die Implementierungen paketprivat sind, müssen Sie die Komponententestklassen im selben Paket platzieren, wenn Sie sie direkt testen möchten. Wenn Sie Ihre Unit-Test-Klassen in einem anderen Paket haben, haben Sie von Ihren Tests aus nur direkten Zugriff auf die öffentliche Schnittstelle und die Factory-Klasse.

KOMME AUS
quelle
1
"Normalerweise möchten Sie Unit-Tests auch für paketprivate Klassen und Methoden schreiben." Nein! Das ist wirklich eine schlechte Praxis. Private Pakettypen sind Implementierungsdetails und sollten niemals direkt getestet werden. Testen Sie nur öffentliche APIs.
David Arno
1
@ DavidArno Ich bin anderer Meinung. Ich habe jedoch das Wort "normalerweise" durch das Wort "manchmal" ersetzt, um diese spezielle Diskussion zu vermeiden.
Kommen Sie vom
1
Sie sind vielleicht nicht einverstanden, was Sie wollen, aber das Testen des Innenlebens eines Codeteils führt sowohl zu einer engen Kopplung zwischen diesem Innenleben und den Tests als auch zu spröden Tests, die selbst bei einfachem Refactoring leicht brechen. Es ist eine sehr schlechte Praxis.
David Arno
Wenn ich sicherstellen möchte, dass alle meine Transmogrifier-Implementierungen funktionieren, unabhängig davon, was die Factory tut, schreibe ich Komponententests, die jede Implementierung testen. Beachten Sie, dass die Implementierungen über eine gemeinsam genutzte öffentliche API verfügen, obwohl die Klassen paketprivat sind. Dieser Test sollte nicht unterbrochen werden, es sei denn, ich ändere die öffentliche API. Eigentlich würde ich wahrscheinlich einen generischen Test für einen Transmogrifier schreiben und ihn dann für jede Implementierung ausführen. Während es möglich ist, jede Implementierung über die Factory abzurufen, ist es besser, diese Abhängigkeit beim Testen von Transmogrifiers nicht zu haben.
Kommen Sie vom
Dann schauen Sie sich eines Tages an MapTransmogrifierund ListTransmogrifierentscheiden, dass sie zu einer Klasse gemacht werden können. Sie erstellen also ListMapTransmogrifier, ändern die Factory, um diese zu verwenden, und löschen die beiden Klassen. Der Code wird jetzt nicht kompiliert, daher müssen Sie jeden Test in beiden ändern MapTransmogrifierTestund ListTransmogrifierTestzum Kompilieren bringen. Ein Test schlägt fehl. War das darauf zurückzuführen, dass die Tests geändert oder erstellt wurden ListMapTransmogrifier? Heraus kommt der Debugger, um herauszufinden ... alternativ, wenn die Tests die Fabrik verwenden, machen Sie diesen Refactor und alle kompilieren noch ...
David Arno