I've gotten lots of PowerMock tests to work, and it often requires adding a @PrepareForTest annotation and putting various classes in that list. Frankly, I've never really been sure exactly what situations require putting a class into that list. I think I know some of them, but I often end up guessing at this, and probably have sometimes put more classes in that list than are required. It would help if I had a clear idea of when it's required.
--
You received this message because you are subscribed to the Google Groups "PowerMock" group.
To unsubscribe from this group and stop receiving emails from it, send an email to powermock+...@googlegroups.com.
To post to this group, send email to powe...@googlegroups.com.
Visit this group at http://groups.google.com/group/powermock.
For more options, visit https://groups.google.com/d/optout.
Is it also the case that if you mock static methods in a class, you have to prepare both the class with the static methods AND the class calling those static methods?
For some background, I’m currently looking at a test which we’ll call “FooTest”, which is a test for class “Foo”. The “Foo” class uses a “LoggingUtil” class. The test suppresses the static initialization of “LoggingUtil” and mocks all of its static methods (it doesn’t specify any behavior for them). The test also suppresses the static initialization of three other related classes. In at least one of the tests, it needs to mock the ResourceBundle class, which apparently requires a slightly different way of specifying behavior.
In order for the tests to all not fail with errors (not addressing all test assertions as of yet), I have to have this:
@PrepareForTest({Foo.class, LoggingUtil.class})
Note that I have the “Foo” class in this list, the class under test. I’m not mocking any of the methods of Foo.
Here’s an elided excerpt from a relevant test method:
when(resourceBundleService.getResourceBundle(anyString())).thenReturn(rsb);
PowerMockito.doReturn("This item will be ship on {0}").when(rsb).getString(anyString());
The “rsb” is a ResourceBundle object (which is an instance of a “system class”). The “resourceBundleService” is a mock object in my test class.
The following is an elided excerpt from a method called by the “Foo” class during the execution of the test method:
ResourceBundle bundle = getResourceBundleService().getResourceBundle(pLocale);
translatorMsg = bundle != null ? bundle.getString(getDeliveryPromiseKeyMap().get(pDlvryPromiseKey)) : null;
When I step through this last block of code, the “bundle” I get from the first line is the mock object specified from the first “when” in the first block. This is fine. When I step over the second line in this last block, I get the string specified in the second line of the first block. HOWEVER, if my “@PrepareForTest” list does NOT include “Foo.class”, the second line in the second block fails with a “MissingResourceException”, which is thrown from the body of “ResourceBundle.getObject()”, which is called by “ResourceBundle.getString()”. Note that because I removed “Foo.class” frmo the @PrepareForTest list, it then failed to mock the “getString()” method of ResourceBundle. When I add “Foo.class” back in and rerun the test, it works.
So, this appears to violate your guidelines. It appears as if mocking system classes requires “preparing for test” the class making those calls, but that’s just my theory. Do you have an alternative explanation?
Also, can you more clearly define what you mean by “system class”? Does “system class” simply mean anything defined in the bootclasspath, or is it based on the package beginning with “java.*” or “javax.*” (there are other packages besides those in the bootclasspath).
Also, can you provide a little bit of background on why you have to deal with “system” classes differently? I have some ideas, but it would be good to have this spelled out clearly. The PowerMock documentation doesn’t say anything about this that I can see.