127

I have a code somewhat like this below:

Class A {
  public boolean myMethod(someargs) {
    MyQueryClass query = new MyQueryClass();
    Long id = query.getNextId();
    // some more code
  }
}
Class MyQueryClass     {
  ....
  public Long getNextId() {
    //lot of DB code, execute some DB query
    return id;
  }
}

Now I'am writing a test for A.myMethod(someargs). I want to skip the real method query.getNextId() and instead return a stub value. Basically, I want to mock MyQueryClass.

So in my test case, I have used:

MyQueryClass query = PowerMockito.mock(MyQueryClass.class);
PowerMockito.whenNew(MyQueryClass.class).withNoArguments().thenReturn(query);
when(query.getNextId()).thenReturn(1000000L);

boolean b = A.getInstance().myMethod(args);

//asserts

I used @RunWith(PowerMockRunner.class) and @PrepareForTest({MyQueryClass.class}) in the beginning of my test class.

But when I debug the test, it is still calling the real method getNextId() of the MyQueryClass class.

What am I missing here? Can anyone help as I am new to Mockito and PowerMockito.

thecoshman
  • 8,394
  • 8
  • 55
  • 77
user3942446
  • 1,273
  • 2
  • 9
  • 4

3 Answers3

291

You need to put the class where the constructor is called into the @PrepareForTest annotation instead of the class which is being constructed - see Mock construction of new objects.

In your case:

@PrepareForTest(MyQueryClass.class)

@PrepareForTest(A.class)

More general:

@PrepareForTest(NewInstanceClass.class)

@PrepareForTest(ClassThatCreatesTheNewInstance.class)

Jing Li
  • 14,547
  • 7
  • 57
  • 69
TrueDub
  • 5,000
  • 1
  • 27
  • 33
  • 2
    Thanks a lot. It worked now after including the current class Eg A in the @PrepareForTest. – user3942446 Aug 15 '14 at 23:34
  • 2
    I spend a while for this too. Thanks @TrueDub. Because the reference is outdated. I just update it. https://github.com/jayway/powermock/wiki/MockConstructor It says: Use the @PrepareForTest(ClassThatCreatesTheNewInstance.class) annotation at the class-level of the test case. – Victor Choy Feb 29 '16 at 13:05
  • 9
    I have the same problem, but this solution is not working for me – dexter Sep 13 '16 at 08:45
  • 3
    This solution just won't work if you're using eclemma for code coverage. Adding the class under test to @PrepareForTest will result in 0% coverage for that class – ACV Mar 08 '17 at 12:02
  • 3
    The solution will work - the test executes correctly. Obviously eclemma isn't equipped to deal with PowerMockito. Code coverage is not part of this question. – TrueDub Mar 08 '17 at 13:16
  • @ACV - the solution will work. But the code coverage issue with EclEmma plug-in is a known issue with that plug-in. However, you may use Clover if you need to measure code coverage in this kind of scenario. Clover works with PowerMockito. – V.Vidyasagar Mar 30 '17 at 06:52
  • Sonarqube is also showing 0% coverage when I add the class under test to @PrepareForTest. Any idea how we can make Sonarqube pick it? – gbdcool Sep 11 '17 at 19:19
  • @gdbcool Sonarqube just parses coverage results provided to it. You need to look into which coverage tool you're using (Clover, Cobertura, JaCoCo, etc) and investigate whether PowerMockito is supported in the version you're using. If it's not, look into upgrading / converting to something that supports it. As noted above, Clover is one option that works. – JakeRobb Oct 29 '18 at 17:48
9

As @TrueDub mentioned in his accepted reply, you need to add the class where the constructor is called to the @PrepareForTest.

However, if you do this, coverage for that class as reported by eclemma and Sonar will be zero for that class

Powermockito wiki

We are going to replace Javassist with ByteBuddy (#727) and it should help to resolve this old issue. But right now there is NO WAY TO USE PowerMock with JaCoCo On-the-fly instrumentation. And no workaround to get code coverage in IDE.

So the solution here would be to refactor the actual code to use a static factory that would return an instance of that class and then statically mock it.

ACV
  • 9,964
  • 5
  • 76
  • 81
  • Agreed with your comment. – Lathy Feb 12 '19 at 15:22
  • That's not a problem in Intellij though. – ACV Dec 06 '19 at 11:59
  • I believe this only affects the test class where you used this annotation, so you could isolate those tests to minimize impact. I totally agree that the problem really is that the class was not made properly for testing – Calabacin Sep 23 '20 at 15:26
-1

Perhaps you can simply use

Mockito.doReturn(value).when(xxx)