Static class initialization not performed when running JUnit test
Asked Answered
T

2

7

I have a java class with some static fields:

private static final PDMapCacheDAO REST_CACHE_DAO = 
    new PDMapCacheDAOImpl( Constants.REST_CACHE_NAME );

private static final PDMapCacheDAO HOLIDAYS_CACHE_DAO = 
    new PDMapCacheDAOImpl( Constants.HOLIDAYS_CACHE_NAME );

private static final String[] DATE_ARRAY = { "D", "0", "1", "2", "3", "C" };

and the JUnit test mocks that initialization behaviour for REST_CACHE_DAO and HOLIDAYS_CACHE_DAO:

final PDMapCacheDAOImpl holidaysMapCacheDAOImpl = mock(PDMapCacheDAOImpl.class);
final PDMapCacheDAOImpl restMapCacheDAOImpl = mock(PDMapCacheDAOImpl.class);

whenNew(PDMapCacheDAOImpl.class).withArguments(Constants.HOLIDAYS_CACHE_NAME).thenReturn(holidaysMapCacheDAOImpl);
whenNew(PDMapCacheDAOImpl.class).withArguments(Constants.REST_CACHE_NAME).thenReturn(restMapCacheDAOImpl);

When the tests are executed individually, the tests perform as expected, but when all JUnit tests are executed together (from the Java Project with Run As --> Junit Test) the test gives an null pointer exception.

I have done some debugging and I've found out that the problem (as stated in the title) is that the static classes aren't initialized - when the static methods are invoked the REST_CACHE_DAO and HOLIDAYS_CACHE_DAO are null. The constructor of PDMapCacheDAOImpl is not invoked and the mocks are not injected, hence when we use them, it gives a NPE.

I've read about some tools to performs test, like eclemma that have this error (some static classes are not initialized). In this case the solution is to include the -f option.

This is what the Eclemma website says about this problem:"

2.8. How is class coverage defined by EMMA? First of all, a class needs to be considered executable to even be considered for coverage. An executable class is considered to have been covered if it has been loaded and initialized by the JVM. Class initialization implies that the class static constructor (if any) is executed. Note that a class can be covered even though none of its other methods has been executed. It is common to see a small number of loaded but uninitialized classes when you use emmarun without the -f option. EMMA reports class coverage so that you could spot classes that do not seem to be "touched" by your test suite: they could be either dead code or in need of more test attention.

The interesting thing is that we are not using Eclemma, we are using Cobertura, but the behaviour and the errors are the same.

Does anyone know something about this error in Cobertura and how to solve it? (Either in Cobertura or in a generic way)?

Tomokotomorrow answered 1/2, 2013 at 9:7 Comment(5)
As you can see using static fields for object dependencies is a bad design. Hard testing is one of the evidences. Use instance variables for dependencies and then @InjectMocks will do the trick. You'll probably have more issues with that. This is why DI frameworks like Spring, Guice or CDI were invented.Dearth
Which version of Eclipse (and java) are you using?Sadiras
for this development we are not allowed to use spring (i really like spring, but you know, these big enterprises ...) the point is that all of the functionality of our class is static, all methods are static. But, even in the case it is a bad practice, why this error could happen??Tomokotomorrow
we are using Java 6. And the version of eclipse, we have a modified version of eclipse created in the corporation i work. in fact, they translated it into spanish, which i hate because it's more difficult to find all the staff. They even change the name, the only thing i can know is that it is Version: 2.0 Build id: 20110218-0911, but i think this might refer to the platformed version of the organizationTomokotomorrow
Have you tried moving the classes so that they are above your static initializers?Neidaneidhardt
I
0

This is speculative.

I guess PDMapCacheDAO is an interface/abstract class, which uses PDMapCacheDAOImpl for some constants.

And class PDMapCacheDAOImpl implements/extends PDMapCacheDAO. Right?

As I find this a technically ugly solution (reciproke dependencies), make a separate interface PDMapCacheDAOs with these constants.

That might solve the problem.

Inellineloquent answered 1/2, 2013 at 9:59 Comment(3)
no, the PDMapCacheDAOImpl is not used for constants. They are just an interface and its implementation. Then the PDMapCacheDAOImpl access one or other data repository depending on the constructor parameter (Constants.HOLIDAYS_CACHE_NAME or Constants.REST_CACHE_NAME). where are the reciproke dependencies?? thanks for the quick responseTomokotomorrow
So DATE_ARRAY also is null. Sorry, the pattern looked quite familiar: interface T { static final T A = new TImpl(); } against class TImpl implements T { }, which would be nightmarish.Inellineloquent
yes, the DATE_ARRYA also is null. Anyway, thanks for your timeTomokotomorrow
T
0

At the end we have decided to use Singleton instead and avoid all the problems with the static initialization. I have to say to the corporation that the problem remains and can happen again in the future, but i can't wait for the SQA team to fix it.

Thanks for all your responses and your time

Tomokotomorrow answered 1/2, 2013 at 12:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.