Open ziccardi opened 7 years ago
The same happens with PowerMock 1.6.6.
I think this is related to #698, however the stack overflow happens when invoking it first time.
Try @PrepareOnlyThisForTest
instead of @PrepareForTest
I came across the same problem with PowerMock 1.6.5. I can reproduce the bug in the example above, using @PrepareOnlyThisForTest
doesn't help, but the test passes if I replace
@PrepareForTest({ ClassToBeTested.class })
with
@PrepareForTest({ UselessParent.class })
Something similar happens with covariant return types: Foo.java
public class Foo extends Bar {
public Integer foo() {
return 2;
}
}
Bar.java
public class Bar {
public Object foo() {
return 1;
}
}
MyTest.java
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
public class MyTest {
@PrepareForTest( { Foo.class } )
@Test
public void testFoo() {
final Foo objectUnderTest = PowerMockito.mock(Foo.class);
PowerMockito.when(objectUnderTest.foo()).thenCallRealMethod();
final Integer retval = objectUnderTest.foo();
}
}
gives the same error. After changing the return type of Bar.foo
from Object
to Integer
, MyTest.testFoo
passes. And just as in the above example, if I change the annotation from
@PrepareForTest( { Foo.class } )
to
@PrepareForTest( { Bar.class } )
(leaving Object
as the return type of Bar.foo
), the test also passes.
Does this mean that when using PowerMock to mock a subclass, the @PrepareForTest
annotation should always contain only its parent, and not the class itself? Or should both annotations always work and this is a bug?
At least in my above example, nothing is actually mocked and Powermock is not needed, but this modification seems more worrying: Foo.java
public class Foo extends Bar {
public Integer foo() {
return bar();
}
}
Bar.java
class Bar {
public Object foo() {
return 1;
}
public Integer bar() {
return 5;
}
}
MyTest.java
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
public class TestForFoo_foo___Ljava_lang_Integer_ {
/*
* Test generated by Diffblue Deeptest.
* This test case covers the entire method.
*/
@PrepareForTest( { Foo.class } )
@Test
public void fooOutputPositive000d2dc46aa55a955b9() {
// Arrange
final Foo objectUnderTest = PowerMockito.mock(Foo.class);
PowerMockito.doCallRealMethod().when(objectUnderTest);
objectUnderTest.foo();
PowerMockito.when(objectUnderTest.bar()).thenReturn(100);
// Act
final Integer retval = objectUnderTest.foo();
// Assert result
Assert.assertEquals(new Integer(100), retval);
}
}
Here, the method Foo.bar
is being mocked, which is inherited from Bar
. But since Bar
is not public, bar()
is actually copied into the bytecode of Foo
, so manipulating the bytecode of Foo
(rather than just Bar
) seems to make sense here? But again, this test causes the StackOverflowError. And again, replacing
@PrepareForTest( { Foo.class } )
with
@PrepareForTest( { Bar.class } )
makes the test pass.
I've tried Powermock versions 1.6.5, 1.6.6, 1.7.0 and 1.7.4 now, they all give me the same error.
Powermock 2.0.2 and Mockito 2.28.2
I resolved this issue by removing the parent class from @PrepareForTest
.
PowerMock : Version 1.6.4 OS: Mac OS Sierra
When you try to test a method that invokes a parent method with the same name, you get a StackOverflowError.
Follows code to reproduce the issue:
UselessParent.java:
ClassToBeTested.java:
MyTest.java
When you run the test you get a StackOverflowError: