I'm doing some unit tests with JUnit, PowerMock and Mockito. I have a lot of test classes annotated with @RunWith(PowerMockRunner.class)
and @PrepareForTest(SomeClassesNames)
to mock final classes and more than 200 test cases.
Recently I've run into a problem of a PermGen space overflow when I run my entire test suite in Eclipse or Maven2. When I run my test one by one then each of them succeeds.
I did some research about that, however none of the advice helped me (I have increased PermGenSize and MaxPermSize). Recently I've found out that there is one class that contains only static methods and each method returns object mocked with PowerMockito. I'm wondering whether it is a good practice and maybe this is the origin of the problem because static variables are being shared between unit tests?
Generally speaking is it a good practice to have a static class with a lot of static methods which returns static mocked objects?
As @Brice says, the problems with PermGen will be coming from your extensive use of mocked objects. Powermock and Mockito both create a new class which sits between the class being mocked and your test code. This class is created at runtime and loaded into PermGen, and is (practically) never recovered. Hence your problems with the PermGen space.
To your question:
1) Sharing of static variables is considered a code smell. It's necessary in some cases, but it introduces depdendencies between tests. Test A needs to run before test B.
2) Usage of static methods to return a mocked object isn't really a code smell, it's a attern which is often used. If you really can't increase your permgen space, you have a number of options:
Use a pool of mocks, with PowerMock#reset()
when the mock is put back into the pool. This would cut down on the number of creations you're doing.
Secondly, you said that your classes are final. If this is changeable, then you could just use an anonymous class in the test. This again cuts down on the amount of permgen space used:
Foo myMockObject = new Foo() {
public int getBar() { throw new Exception(); }
}
Thirdly, you can introduce an interface (use Refactor->Extract Interface in Eclipse), which you then extend with an empty class which does nothing. Then, in your class, you do similar to the above. I use this technique quite a lot, because I find it easier to read:
public interface Foo {
public int getBar();
}
public class MockFoo implements Foo {
public int getBar() { return 0; }
}
then in the class:
Foo myMockObject = new MockFoo() {
public int getBar() { throw new Exception(); }
}
I have to admit I'm not a particular fan of mocking, 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 on this point of view, see Mocking Mocking and Testing Outcomes. by Uncle Bob
By the way, in maven surefire, you can always forkMode=always which will fork the jvm for each test class. This won't solve your Eclipse problem though.