Reputation: 1281
I have made a small example of my code to illustrate the problem
public class SiteTranslator {
Integer id;
//Other fields
}
public class SiteUtil {
private static SiteTranslator siteTranslator = getSiteTranslator();
private static SiteTranslator getSiteTranslator()
{
SiteTranslator siteTranslator;
//Logic involving network call
return siteTranslator;
}
private static String getEnvironment()
{
String env = "";
//Logic
return env;
}
public static int getParent(int siteId)
{
int parentId = 0;
//Logic using siteTranslator from getSiteTranslator()
return parentId;
}
}
public class SiteUtilTest {
@Test
public void test1()
{
try
{
PowerMockito.suppress(SiteUtil.class.getMethod("getSiteTranslator"));
BDDMockito.given(SiteUtil.getParent(1)).willReturn(6);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
The SiteTranslator object we get from getSiteTranslator() method is used by my public function getParent(). Since getSiteTranslator() requires a network call , it needs to be suppressed. I however get the following error
java.lang.NoSuchMethodException: SiteUtil.getSiteTranslator()
I believe the problem is because I'm trying to mock a private static function. However I cannot change it to public. Is there a way to mock the code in its current state.
Upvotes: 1
Views: 1041
Reputation: 140525
The answer by "Spotted" already nails it, as the core problem is: you created hard-to-test code for absolutely no reason.
Using such internal static calls simply makes your program hard to test; and surprise: it also makes it hard to maintain, enhance, reuse. The fact that you need to turn to Powermock is very often simply an indication that your production code is bad. Now you can choose between using PowerMock to "fix" that problem; or to really fix the problem, by changing your production code - it is simply bad practice to solve problems the way your example code does!
So, the other real lesson here is: you want to spend some time to learn how to write code that does not have such problems; for example by watching those videos.
Upvotes: 1
Reputation: 4091
In fact, you don't need Powermockito to achieve what you need.
At the moment, you think you need Powermockito to suppress a private static method but this is definitely not the way to go.
Instead you should refactor your code to make it easier to test:
static
qualifiersAfter such a refactor, you end up with something like that (no mocking needed !):
public class SiteUtil {
private SiteTranslator siteTranslator;
public SiteUtil(SiteTranslator siteTranslator) {
this.siteTranslator = siteTranslator;
}
public int getParent(int siteId) {
int parentId = 0;
// Logic using siteTranslator
return parentId;
}
...
}
Now you can test it like that:
public class SiteUtilSpec {
private final SiteTranslator defaultTranslator = new DummySiteTranslator();
@Test
public void itShouldReturnTheSixthSiteWhenWeProvideTheFirstParent() {
SiteUtil site = new SiteUtil(defaultTranslator);
int parentId = site.getParent(1);
assertEquals(6, parentId);
}
}
DummySiteTranslator
is a fake object (maybe it is embedding a bunch of hardcoded translations useful for testing) but the point is that this object never do any network call ! Making its usage safe and fast (ideal for testing).
Upvotes: 2