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.
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
qualifiers After 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).
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 .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.