1
votes

I'm having problem when I try to test a method and mock its dependency with PowerMock and Mockito. I've tried to transform the dependency method into a nonstatic method and to use @Mock annotation and @InjectMocks but with no result at all.

Here is the class and method under test:

/* class to be tested */
public class LoginServiceImpl implements LoginService{

   /* method to be tested */
   @Override
   public String createJwt(String subject, String name, String permission, Date datenow)  throws java.io.UnsupportedEncodingException{
       Date expDate = datenow;
       expDate.setTime(datenow.getTime()+(300*1000));  //expiration time = 30 minutes

       String token = jwtUtils.generateJwt(subject, expDate, name, permission);
       return token;
   }
}

Here there is the Dependency I want to Mock and which I am having troubles mocking:

/* Dependency I cannot mock */
public class JwtUtils {

    public static String generateJwt(String subject, Date date, String name, String scope) throws java.io.UnsupportedEncodingException{
        String jwt = Jwts.builder()
            .setSubject(subject)
            .setExpiration(date)
            .claim("name", name)
            .claim("scope", scope)
            .signWith(
                    SignatureAlgorithm.HS256,
                    "myPersonalSecretKey12345".getBytes("UTF-8")
            )
            .compact();

       return jwt;
   }
}

And here at last, but not least, the test class with the test method which fails. I have to say that it doesn't even reach the assert method call, but fails at when().thenResult(). I have also to specify that I've tried to use doReturn() and any() as matcher, but with not result.

@RunWith(MockitoJUnitRunner.class)          //to run Mockito
@PrepareForTest({JwtUtils.class})           //powerMock annotations tomock classes containing static methods
public class LoginServiceImplTest {

   @InjectMocks
   LoginServiceImpl loginService;          //System under test (SUT)

   @Test
   public void createJwtTest() throws Exception {

       SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd");
       Date expdate = ft.parse("2040-12-12");
       String jwt = JwtUtils.generateJwt("BDAGPP32E08F205K", expdate, "Pippo Baudo", "conduttore");
       //HERE IT'S WHERE IT FAILS:
       when(JwtUtils.generateJwt("BDAGPP32E08F205K", expdate, "Pippo Baudo", "conduttore")).thenReturn(jwt);

       assertThat(loginService.createJwt("BDAGPP32E08F205K", "Pippo Baudo", "conduttore", expdate), is(jwt));
   }
}

Here there is the error JUnit and Mockito gives to me:

org.mockito.exceptions.misusing.MissingMethodInvocationException: when() requires an argument which has to be 'a method call on a mock'. For example: when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because: 1. you stub either of: final/private/equals()/hashCode() methods. Those methods cannot be stubbed/verified. Mocking methods declared on non-public parent classes is not supported. 2. inside when() you don't call method on mock but on some other object.

at com.example.bytecode.SpringBootJWT.services.LoginServiceImplTest.createJwtTest1(LoginServiceImplTest.java:114) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37) at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Process finished with exit code 255

2
Try when(JwtUtils::generateJwt)Usagi Miyamoto
Also your createJwt() method modifies argument datenow...!Usagi Miyamoto
thank you, but it didn't worked for meAlex Mawashi

2 Answers

3
votes

Try replacing @RunWith(MockitoJUnitRunner.class) with @RunWith(PowerMockRunner.class). As far as I'm aware, all tests which use PowerMock features must be run with PowerMockRunner.

1
votes

There is no such rule that methods in utility classes must be static!

In fact it is a bad practice because it makes your code highly coupled and inflexible. You problems replacing this dependency are a prove of that.

So instead surrendering to your bad design and using PowerMock you should apply inversion of control by removing the static key word from the method an pass in an instance of that class into your unit, preferably using a DI framework. In that case you could use plain Mockito to mock that dependency and had no issues replacing it.