2

To mock a static method powermock giving an exception while expect().

@Test
public void testRegistrarService()
{
   mockStatic(IdGenerator.class);
   expect(IdGenerator.generateNewId()).andReturn(42L);
   long actualId=serTestObj.registerService();
   replay(IdGenerator.class);
   verify(IdGenerator.class);
   assertEquals(42L,actualId);
 }


public class ServiceRegistrator
{
public long registerService()
{
    long id = IdGenerator.generateNewId();
    return id;
 }
}

public class IdGenerator
{
  public static long generateNewId()
  {
    return System.currentTimeMillis();
  }
}

Exception is:

java.lang.IllegalStateException: no last call on a mock available
at org.easymock.EasyMock.getControlForLastCall(EasyMock.java:521)
at org.easymock.EasyMock.expect(EasyMock.java:499)
at  home.powermock.testServiceRegistrator.testRegistrarService(testServiceRegistrator.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at com.intellij.rt.execution.junit2.JUnitStarter.main(JUnitStarter.java:31)

how to mock staic method,while m using powerMock i'm using intelliJ idea,how to resolve that exception.

SachG
  • 105
  • 1
  • 2
  • 12
  • Is `IdGenerator.generateNewId()` a `final` method? If so, http://stackoverflow.com/questions/3494969/easymock-3-0-mocking-class-throws-java-lang-illegalstateexception-no-last-call is a duplicate. Alternatively, you've perhaps missed out calling `EasyMock.replay`. – Duncan Jones Jun 25 '13 at 09:41
  • i'm calling replay method here like replay(IdGenerator.class); but it got missed out here.. – SachG Jun 25 '13 at 09:46
  • IdGenerator.generateNewId() is not a final method.its only static method. – SachG Jun 25 '13 at 09:46

4 Answers4

7

Your code is missing the annotation

@PrepareForTest(IdGenerator.class)
JoseK
  • 31,141
  • 14
  • 104
  • 131
  • @RunWith(PowerMockRunner.class) @PrepareForTest({testServiceRegistrator.class,IdGenerator.class} i already added both annotation before class in which test method is present. – SachG Jun 25 '13 at 11:09
  • remove the testServiceRegistrator.class from the list – JoseK Jun 25 '13 at 12:17
  • removed...still the same exception.. :( now i have like @PrepareForTest(IdGenerator.class).. i think that the root cause is in "expect()" method.Bcz exception is coming at that point.may be some thing is cooking here. but not able to resolve it? – SachG Jun 25 '13 at 12:41
  • facing same issue even after putting @PrepareForTest – Sandeep Jan 25 '16 at 12:56
5

In my case I was missing the following method in my test class

   @ObjectFactory
   /**
    * Configure TestNG to use the PowerMock object factory.
    */
   public IObjectFactory getObjectFactory() {
      return new org.powermock.modules.testng.PowerMockObjectFactory();
   }

Once I added it, I got rid of the "no last call on a mock available" error.

gybrush
  • 51
  • 1
  • 1
  • In my case, it got rid of the original error message and replaced it with "Inconsistent stackmap frames at branch target 49" ... I'd love to hear a bit more about the reasoning behind adding the IObjectFactory. – Chris Aug 02 '16 at 16:19
  • I'm using testng, not junit and added the RunWith. I took that out and adding the ObjectFactory seems to have me on my way. I got some insight here: https://github.com/jayway/powermock/wiki/TestNG_usage – Chris Aug 02 '16 at 16:50
4

You need to put the replay before the actual call to the method.

EDIT: I think part of the problem may be caused because of your imports. Try not to import static powermock and static easymock (I've found that I often confuse myself and forget which one I need to call replay on).

Try running the following code. If it doesn't run correctly, then it may be because of a problem with the particular version of PowerMock/EasyMock/Junit that you have.

TestClass:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.easymock.EasyMock.*;

import static org.junit.Assert.*;
@RunWith(PowerMockRunner.class)
@PrepareForTest(IdGenerator.class)
public class TestClass {

@Test
public void testRegistrarService()
{
    ServiceRegistrator serTestObj = new ServiceRegistrator();

    PowerMock.mockStatic(IdGenerator.class);
    expect(IdGenerator.generateNewId()).andReturn(42L);
    PowerMock.replay(IdGenerator.class);
    long actualId=serTestObj.registerService();
    PowerMock.verify(IdGenerator.class);
    assertEquals(42L,actualId);
 }
}

IdGenerator:

public class IdGenerator {
     public static long generateNewId()
      {
        return System.currentTimeMillis();
      }
}

ServiceRegistrator:

public class ServiceRegistrator {
    public long registerService()
    {
        long id = IdGenerator.generateNewId();
        return id;
     }
}
HardcoreBro
  • 425
  • 4
  • 17
  • HardcoreBro i tried your approach.but still the same exception..still not resolved... :( – SachG Jun 26 '13 at 04:48
  • See the revised post. I added source code. I think your problem may be with the way you imported your code... Try changing your imports to match the above code and let me know how it goes – HardcoreBro Jun 26 '13 at 11:22
  • still its not working same exception is coming....is this code working on your environment????? If so it seems to be a jar problem...then please let me know once which jar are you using for EasyMock/PowerMock/JUnit.... – SachG Jun 26 '13 at 11:56
  • 1
    The code works in my environment. I'm going to list everything that I have imported, but there might be something that I'm using that isn't absolutely necessary: powermock-api-easymock-1.4.10.jar hamcrest-core-1.3.jar junit--4.11.jar platform.jar powermock-module-junit4-1.4.10.jar powermock-module-junit4-common-1.4.10.jar powermock-core-1.4.10.jar powermock-api-support-1.4.10.jar easymock-3.0.jar javassist-3.15.0-GA.jar powermock.reflect-1.4.10.jar objenesis-1.2.jar cglib-nodep-2.2.jar – HardcoreBro Jun 26 '13 at 13:41
  • HardCoreBro..i'm using almost same jar.but don't know why still facing same exception....Dear Can you please mail me this all jar to my gmail id.... "sachingrover2@gmail.com" ...please mail all the impoted jars..thanks – SachG Jun 27 '13 at 05:36
4

This question has been here for a long time but I'll try to give to it an aswer to explain what i did to resolve this problem.

First of all you have to use these two annotations:

@RunWith(PowerMockRunner.class)

This annotation let the current test class know what to use to run his tests, this is useful because we can use PowerMockRunner instead of JUnitRunner

@PrepareForTest(IdGenerator.class)

This annotation is used to prepare the class "IdGenerator" to be used in the test, prepare means that we will be able to mock the static methods as we do to the public methods

After added these two annotations we have to be sure we are using the right packages provided by PowerMock:

1) PowerMock:

  • Import: import org.powermock.api.easymock.PowerMock;
  • Use: We will use PowerMock to mock (and not only) our static method with the following code line

    PowerMock.mockStatic(IdGenerator.class);

2) EasyMock:

  • Import: import org.easymock.EasyMock;
  • Use: We are going to use EasyMock to fake our object to be returned by our static method:

    EasyMock.expect(IdGenerator.generateNewId()).andReturn(42L);

These was two examples on what are used PowerMock and EasyMock, and here I'll try to explain the code and what it does:

mockStatic(IdGenerator.class);
//We mock our IdGenerator class which have the static object

expect(IdGenerator.generateNewId()).andReturn(42L);
//We fake our method return object, when we'll call generateNewId()
//method it will return 42L
//With expecting we "record" our this method and we prepare it to be     
//changed (it will return our decided value)

replay(IdGenerator.class);
//We go to perform our methods "registered" with the expect method
//inside the IdGenerator class, in this case with replay we just apply
//the changes of the expect to the method generateNewId()

long actualId = serTestObj.registerService();
//We create our object (which inside have a non static method that
//use generateNewId() static method)

verify(IdGenerator.class);
//We verify that the our faked method have been called

assertEquals(42L,actualId);
//We see if the two values are matching

Pay attention because replay must be used before you create the new object (actualId in this example) that will call the static faked methods.

Also do a lot of attention on what you are importing, for a distraction i was using

PowerMockito.mockStatic(className.class);
//from import org.powermock.api.mockito.PowerMockito;

Instead of

PowerMock.mockStatic(className.class);
//from import org.powermock.api.easymock.PowerMock;

I hope that this answer is clear and complete

By the way here i'll refer you to some useful links:

PowerMock Static Documentation on GitHub

Mvn Repository PowerMock Libraries

See you :D