ChatGPT解决这个技术问题 Extra ChatGPT

Using PowerMockito.whenNew() is not getting mocked and original method is called

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.


J
Jing Li

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)


Thanks a lot. It worked now after including the current class Eg A in the @PrepareForTest.
I spend a while for this too. Thanks @TrueDub. Because the reference is outdated. I just update it. github.com/jayway/powermock/wiki/MockConstructor It says: Use the @PrepareForTest(ClassThatCreatesTheNewInstance.class) annotation at the class-level of the test case.
I have the same problem, but this solution is not working for me
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
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.
A
ACV

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.


Agreed with your comment.
That's not a problem in Intellij though.
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
j
jiajianchen

Perhaps you can simply use

Mockito.doReturn(value).when(xxx)