JUnit 4 PermGen Größe überlauf bei der Ausführung von tests in Eclipse und Maven2
Mache ich einige unit-tests mit JUnit, PowerMock und Mockito. Ich habe eine Menge von test-Klassen versehen mit @RunWith(PowerMockRunner.class)
und @PrepareForTest(SomeClassesNames)
zu verspotten, Finale Klassen und mehr als 200 Testfälle.
Vor kurzem habe ich ein problem einer der PermGen space overflow, wenn ich meine gesamte Testsuite in Eclipse und Maven2. Wenn ich meine test eins nach dem anderen dann wird jeder von Ihnen schafft es.
Ich habe einige der Forschung über das aber keiner der Ratschläge hat mir geholfen (ich habe erhöhte PermGenSize und MaxPermSize). Vor kurzem habe ich herausgefunden, dass es eine Klasse enthält nur statische Methoden, und jede Methode gibt Objekt verspottet mit PowerMockito. Ich Frage mich, ob es eine gute Praxis, und dies ist vielleicht der Ursprung des Problems, weil statische Variablen werden gemeinsam von unit-tests?
Generell ist es eine gute Praxis, haben eine statische Klasse mit vielen statischen Methoden gibt statische verspottet Objekte?
- Gibt es einen Grund, warum Ihre Anwendung konzipiert wurde, bei so vielen statischen Methoden? Statische Methoden neigen dazu, machen Tests schwierig. Wäre es möglich für Sie zu haben, diese als nicht-statische Methoden einer Klasse; dann Spritzen Sie ein Objekt der Klasse, was auch immer code, den Sie haben, die es braucht?
- Ich würde davon ausgehen, von dem, was der OP sagte, dass die statischen Methoden in den tests verwendet werden, werden Sie nur verspottet Objekte. Sie werden nicht verwendet, in der nicht-test-code.
- OK, ich lese es anders. @Adam, könntest du bitte klären? Sind die statischen Methoden in Ihrer Anwendung, oder einfach nur testen, Gerüste?
- Um zu klären, statische Methoden sind Teil der test-Gerüst.
- Warum? Kannst du nicht nur machen Sie nicht-statische Methoden in beliebiger test-Klasse, in der Sie Leben?
- Ich habe es geändert aber es half nicht viel 🙁
Du musst angemeldet sein, um einen Kommentar abzugeben.
Als @Brice sagt, die Probleme mit der PermGen kommen aus Ihren umfangreichen Einsatz von verspottet Objekte. Powermock und Mockito beide erstellen eine neue Klasse, die sitzt zwischen der Klasse verspottet und Ihr test-code. Diese Klasse wird zur Laufzeit geladen und in der PermGen, und ist (praktisch) nie wieder erholt. Daher deine Probleme mit der PermGen space.
Zu deiner Frage:
1) gemeinsame Nutzung von statischen Variablen wird als ein code smell. Es ist notwendig, in einigen Fällen, aber es bringt depdendencies zwischen den tests. Test Eine laufen muss bevor test B.
2) Verwendung von statischen Methoden, um wieder eine ironisierte Objekt ist nicht wirklich ein code, der Geruch, es ist eine attern, die Häufig verwendet werden. Wenn Sie wirklich können nicht erhöhen Sie Ihre permgen space, haben Sie eine Reihe von Optionen:
Verwenden Sie einen pool von mocks, mit
PowerMock#reset()
als der Entwurf wieder in den pool. Dies würde reduzieren auf die Anzahl der Kreationen, die Sie tun.Zweitens, Sie sagte, dass Ihre Klassen sind endgültig. Ist dies veränderbar, dann könnte man nur eine anonyme Klasse im test. Dies wiederum verkürzt sich auf die Menge der permgen space verwendet:
Drittens, Sie können sich vorstellen, eine Schnittstelle (benutzen Sie Refactor - ->Entpacken-Schnittstelle in Eclipse), die du dann erweitern mit einer leeren Klasse, die tut nichts. Dann, in Ihrer Klasse, Sie ähnlich wie oben. Ich verwende diese Technik sehr viel, weil ich finde es einfacher zu Lesen ist:
dann in der Klasse:
Ich muss zugeben, ich bin kein besonderer fan von Spott, ich benutze es nur, wenn es notwendig ist, Neige ich dazu, entweder die Klasse erweitern, die mit einer anonymen Klasse, oder erstellen Sie eine echte MockXXX Klasse. Für weitere Informationen zu dieser Sicht finden Sie unter Verspotten, zu Verhöhnen und Testen die Ergebnisse. von Onkel Bob
Durch die Art und Weise, in der maven-surefire, können Sie immer forkMode=immer die Gabel der jvm für jede test-Klasse. Diese lösen nicht Ihre Eclipse-problem, obwohl.
Ich bin immer PermGen-Fehler von Junit in Eclipse zu. Aber ich bin nicht mit jedem Spott-Bibliotheken wie Mockito noch EasyMock. Aber, meine code-Basis ist groß und meine Junit-tests mit Spring-Test (und sind Intensive und komplexe Testfälle). Für diese brauche ich, um wirklich erhöhen Sie den PermGen für alle meine Junit-tests.
Eclipse gilt die Installierte JRE-Einstellungen, um die Junit-läuft - nicht die eclipse.ini-Einstellungen. So ändern Sie diese:
Dieser Einstellung können Junit-tests ausgeführt werden, desto intensiver Testfälle in Eclipse, und vermeiden Sie den OutOfMemoryError: PermGen. Dies sollte auch mit geringem Risiko, weil die meisten einfache Junit-tests nicht weisen, dass der Speicher.
Erste : Mockito ist mit CGLIB zum erstellen von mocks und PowerMock ist mit Javassist für einige andere Sachen, wie das entfernen der Letzte Marker, Powermock, lädt Klassen in einen neuen ClassLoader. CGLIB ist bekannt für das Essen die Permanente Generierung (nur google CGLIB PermGen um relevante Ergebnisse auf der Rolle).
Es ist nicht eine gerade Antwort, denn es hängt davon ab, details in Ihrem Projekt zu :
Wie gesagt es gibt statische helper-Klasse, ich weiß nicht, ob der hält, statische Variablen mit mocks als gut, ich weiß nicht, die details des Codes, also das ist Reine Vermutung, und die anderen Leser, die eigentlich besser weiß mag mich korrigieren.
Könnte es sein, den ClassLoader (und zumindest einige seiner Kinder), die geladen diese statische Klasse kann am Leben erhalten werden, über tests - es könnte sein, weil die Statik (was lebt in der Klasse Reich) oder weil einige Referenz-irgendwo - das bedeutet, dass wenn der ClassLoader lebt noch (d.h. nicht garbage Collection) seine geladene Klassen werden nicht verworfen d.h. die Klassen einschließlich der generierten sind noch in der PermGen.
Diese Klassen könnten auch riesig sein in der Größe, wenn Sie eine Menge von diesen Klassen geladen werden, das relevant sein könnte, um höhere PermGen-Werte, vor allem, da Powermock braucht, um neu zu laden Klassen in einen neuen Classloader für die einzelnen tests.
Wieder ich weiß nicht, die details Ihres Projekts, also ich kann nur raten, aber Ihre permanente Generierung Problem kann verursacht werden, entweder durch Punkt 1 oder Punkt 2, oder auch beide.
Sowieso generell würde ich ja sagen : eine statische Klasse, die könnten zurückkehren statische verspottet Objekt sieht aus wie eine schlechte Praxis hier, da es in der Regel in der Produktion code. Wenn Sie schlecht gestaltete, kann es führt zu ClassLoader, der ist undicht (das ist böse!).
In der Praxis habe ich gesehen, mit Hunderten von tests (mit Mockito) ohne sich ständig ändernden Speicher-Parameter und ohne dass der CGLIB-proxies, die entladen wird, und ich bin nicht mit statischen Sachen appart aus der Mockito-API.
Wenn Sie mit einer Sun/Oracle-JVM können Sie versuchen, diese Optionen zu verfolgen, was passiert :
-XX:+TraceClassLoading
und-XX:+TraceClassUnloading
oder-verbose:class
Hoffe, das hilft.
Außerhalb des Geltungsbereichs dieser Frage :
Personnaly ich mag es nicht verwenden, um zu verwenden, Powermock wie auch immer, ich verwende nur in Ausnahmefällen z.B. für die Prüfung unveränderbar legacy-code. Powermock ist zu aufdringlich meiner Meinung nach, hat es zu spawn für jeden test einen neuen classloader zu führen seine Taten aus (ändern des bytecode), müssen Sie stark mit Anmerkungen versehen die test-Klassen in der Lage sein zu spotten, ...
Meiner Meinung nach für übliche Entwicklung, alle diese kleinen Unannehmlichkeiten outweight den Vorteil, die hability um mock-Finale. Auch Johan der Autor von Powermock, sagte mir einmal, er war recommanding Mockito statt und halten Powermock für einen bestimmten Zweck.
Versteh mich nicht falsch hier: Powermock ist ein fantastisches Stück Technik, dass wirklich helfen, wenn Sie es zu tun haben mit (schlecht) konzipiert, legacy-code können Sie nicht ändern. Aber nicht für jeden Tag developpement, vor allem, wenn TDD üben.
java.lang.instrument
, die erfordert das laden eines Java-Agenten in die JVM ausgeführt. Dies ist jedoch für die Benutzer transparent, das heißt, Sie müssen nicht fügen Sie eine-javaagent
parameter. (Andere Agenten-basierte tools benötigen, aber das ist nur, weil Sie sich nicht nutzen Sie die Attach-API.)-javaagent
parameter. (In der Tat, was passiert ist, dass einige Projekte noch deploy zu einem Java-5-server, aber das bedeutet nicht verhindern, dass Sie sicher ausführen von tests in der Entwicklung/bauen Maschinen mit JDK 1.6 oder sogar noch höher -, nur "javac -source 1.5 -target 1.5".)