JUnit 4 PermGen overflow on test execution in Eclipse and Maven2

I am doing some unit tests with JUnit, PowerMock and Mockito. I have many test classes annotated with @RunWith(PowerMockRunner.class) and @PrepareForTest(SomeClassesNames) to make fun of the final classes and over 200 test cases.

I recently encountered a PermGen space overflow problem when I run the entire test suite in Eclipse or Maven2. When I run my test one by one, each of them succeeds.

I did some research on this, however, none of the tips helped me (I increased PermGenSize and MaxPermSize). I recently found out that there is one class that contains only static methods, and each method returns an object that mocked PowerMockito. I am wondering if this is good practice, and perhaps this is the cause of the problem, because static variables are shared between unit tests?

Generally speaking, is it good to have a static class with many static methods that returns static mocked objects?

+8
static junit permgen mockito powermock
source share
3 answers

As @Brice explains, problems with PermGen will come from your extensive use of scoffing objects. Powermock and Mockito create a new class that sits between the class mocking your test code. This class is created at runtime and loaded into PermGen and hardly restored. Hence your problems with PermGen space.

To your question:

1) The exchange of static variables is considered the smell of code. This is necessary in some cases, but it introduces dependencies between the tests. Test A must be performed before test B.

2) Using static methods to return the mocked object is not really a smell of code, it is often used. If you really cannot increase permento space, you have several options:

Use the rape pool with PowerMock#reset() when the layout returns to the pool. This would reduce the amount of creation you make.

Secondly, you said that your classes are final. If this is mutable, then you can just use an anonymous class in the test. This again reduces the amount of space used pergents:

 Foo myMockObject = new Foo() { public int getBar() { throw new Exception(); } } 

Third, you can enter an interface (use Refactor-> Extract Interface in Eclipse), which then expands with an empty class that does nothing. Then, in your class, you do the above. I use this technique quite a lot because it is easier for me to read:

 public interface Foo { public int getBar(); } public class MockFoo implements Foo { public int getBar() { return 0; } } 

then in class:

 Foo myMockObject = new MockFoo() { public int getBar() { throw new Exception(); } } 

I must admit that I am not a private fan of ridicule, I use it only when necessary, I tend to either extend the class with an anonymous class, or create a real MockXXX class. For more information about this view, see Bullying and Test Results. uncle bob

By the way, in maven surefire you can always forkMode = always , which will fork jvm for each test class. This will not solve the Eclipse problem.

+8
source share

I am getting PermGen errors from Junit in Eclipse. But I do not use any mocking libraries like Mockito or EasyMock. However, my code base is large, and my Junit tests use Spring -Test (and are intense and complex test cases). To do this, I need to truly increase PermGen for all of my Junit tests.

Eclipse applies the installed JRE settings to Junit launches, not to eclipse.ini settings. So, to change those:

  • Window> Settings> Java> Installed JREs
  • select the default JRE button, Edit ...
  • add to default VM arguments: -XX: MaxPermSize = 196m

This option allows Junit tests to run more intense TestCases in Eclipse and avoid OutOfMemoryError: PermGen. This should also be a low risk, because most simple Junit tests will not allocate all this memory.

+23
source share

First: Mockito uses CGLIB to create mocks, and PowerMock uses Javassist for some other things, such as removing final tokens, Powermock also loads classes into the new ClassLoader. CGLIB is known for eating the Permanent Generation (just google CGLIB PermGen to find relevant results on this).

This is not a direct answer, as it depends on the details of your project:

  • As you pointed out, there is a static helper class, I donโ€™t know if it stores static variables with mocks, I donโ€™t know the details of your code, so this is pure conjecture and other readers who actually know better can fix me.

    Maybe the ClassLoader (and at least some of his children) that loaded this static class can be saved in tests - maybe because of the statics (which lives in the class area) or because of some link somewhere- then this means that if the ClassLoader is still alive (i.e. does not collect garbage), its loaded classes are not discarded, i.e. classes, including those generated, are still in PermGen .

  • These classes can also be huge in size, if you have many of these classes to load, this may be related to higher PermGen values, especially since Powermock needs to reload the classes in the new Classloader for each test.

Again, I donโ€™t know the details of your project, so Iโ€™m just guessing, but your problem with the constant generation can be caused either by point 1 or point 2, or even both.

In any case, I would say yes: a static class that could return a static mocked object looks like bad practice here, as is usually done in production code. If it is poorly crafted, it can lead to a ClassLoader leak (this is nasty!).

In practice, I have seen hundreds of tests (only with Mockito), without changing the memory settings, and without observing that CGLIB proxies are unloaded, and I do not use static things, and not the ones used in the Mockito API.

If you are using the Sun / Oracle JVM, you can try these options to keep track of what is happening:

-XX:+TraceClassLoading and -XX:+TraceClassUnloading or -verbose:class

Hope this helps.


Out of scope of this question:

Personnaly I still don't like to use Powermock, I only use it in corner cases, for example. for testing immutable legacy code. Powermock is too intrusive imho, it must generate a new classloader for each test to perform its actions (modification of bytecode), you should annotate the test classes to a great extent, so that they can be mocked ... In my opinion, for normal development all these minor inconveniences go off balance in favor of cunning to make fun of the finals. Even Johan, author of Powermock, once told me that he recommended Mockito instead and kept Powermock for some specific purpose.

Don't get me wrong: Powermock is a fantastic technology that really helps when you have to deal with (poorly) developed legacy code that you cannot change. But not for everyday development, especially if it is important for TDD.

+5
source share

All Articles