I'm using PowerMock and I'd like to know how to keep all behavior of the child class, but stub super calls that may be overriden by the child.
Say I have this class:
public class A {
public String someMethod() {
return "I don't want to see this value";
}
}
and a sub class:
public class B extends A {
#Override
public String someMethod() {
return super.someMethod() + ", but I want to see this one";
}
}
How do I stub the call to super.someMethod()?
I've tried
#Test
public void test() {
B spy = PowerMockito.spy(new B());
PowerMockito.doReturn("value").when((A)spy).someMethod();
assertEquals("value, but I want to see this one", spi.someMethod());
}
You can try suppressing the methods from the Parent class,
PowerMockito.suppress(methodsDeclaredIn(A.class));
Here's an article on Stubbing, suppressing and replacing with PowerMock that might be of some use.
https://www.jayway.com/2013/03/05/beyond-mocking-with-powermock/
Don't forget to add #PrepareForTest({ParentClassToSupress.class}) on your test class. Then you can do as Steve suggests and suppress methods in the parent: PowerMockito.suppress(methodsDeclaredIn(ParentClassToSupress.class));
The cast you're attempting is not going to work as you are expecting. However, I think you have a couple of options to get around this, certainly with PowerMockito.
Take a look at this StackOverflow answer.
Related
Let's say I have a class like this:
//this is src/a/b
package a.b;
class C
{
protected Api getApi();
}
and test like this:
//and this is test/a/d
package a.d;
class TestE {
#Test
public void test()
{
C mockedC = spy(new C());
doReturn(*somemockedapi*).when(mockedC).getApi(); // this one doesn't work!
.....
}
}
It will work if class in tests is in tests/a/b, but this is not a solution because we need access to some stuff from src/a/d. And obviously this function is accessible via inheritance, so is there any way to let mockito mock it in such case?
This is potentially quite dangerous, but can be done.
//reflectively get the method in question
Method myMethod = mockedC.getClass().getDeclaredMethod("getApi");
//manually tell java that the method is accessible
myMethod.setAccessible(true);
//call the method
myMethod.invoke(myClass, null);
//PLEASE SET THE FIELD BACK TO BE UNACCESSIBLE
myMethod.setAccessible(false);
Sometimes when I write unit tests I should to mock reference to superclass.
I have read this question:
question
This answer answer with DI advice to refactor code. But I cannot it
this answer another answer is not suitable if superclass method is enough big. In my case I have very big code. Yes I know that it is brokes SOLID OOD principes but I just should to write test. I have not enough time for refactor.
said question was asked 4 years ago!
Does currently Mockito or Powermock can resolve this issue ?
update
code example:
class BaseService {
public void save() {
// a lot of code here! I cannot change this code.
}
}
public Childservice extends BaseService {
public void save(){
//logic for testing
super.save();
//logic for testing
}
}
update 2
public class Parent {
public int save() {
return 99;
}
}
public class Child extends Parent {
public int save() {
int i = super.save();
return i*2;
}
}
and test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(Parent.class)
public class ParentTest {
#Test
public void testSave() {
PowerMockito.suppress(PowerMockito.methodsDeclaredIn(Parent.class));
System.out.println(new Child().save());
}
}
output: 198
With Powermock you can replace or suppress methods, so it is possible to change the action done by BaseService.save(). You can also make methods to do nothing with suppressing. You can even suppress static initializer blocks.
Please read this blog entry of the Powermock authors. See chapter "Replacing".
UPDATE:
Suppress seems to work for me, but replace not. See the picture below:
This is impossible; the whole point of a superclass is that it encapsulates upstream state and functionality, and the class hierarchy is hard-coded in your subclass based on the extends relationship.
Ok so I'm stuck with Mockito again. Here's the situation:
I've a super class, and a subclass:
class Parent {
protected void insertData() {
// Here is some database related stuff
someObject.storeData();
}
}
class Child extends Parent {
private String name;
public void printHierarchy(int x) {
if (x > 1) {
insertData()
} else {
System.out.println("Child");
}
}
}
And in my unit test class, I'm testing Child class printHierarchy() method:
#RunWith(SpringJUnit4ClassRunner.class)
public class ChildTest {
#InjectMocks // To inject mock objects
private Child child = new Child();
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
// This is where the issue is
doNothing().when(child).insertData();
}
#Test
public void testPrintHierarchy() {
child.printHierarchy(5);
// Here also
verify(child, times(1)).insertData();
}
}
So the issue is, how do I verify if insertData() method was called from Child#printHierachy()?
When I try the above code, I get the error as:
Argument passed to when() is not a mock!
Of course, child is not a mock. I'm testing that class. But how do I resolve this issue?
No I haven't found any duplicate of this. One question was pretty similar though, but it didn't help me.
You need to use spy() for that. The following code works:
public final class Bin
{
#Test
public void spyMe()
{
final Child c = spy(new Child());
doNothing().when(c).printParent();
c.printHierarchy(1);
verify(c).printParent();
}
}
class Parent {
protected void printParent() { System.exit(0);}
}
class Child extends Parent {
private String name;
public void printHierarchy(int i) {
if (i > 0)
printParent();
}
}
I think you need to use a spy for Child instead of a mock.
Whether method printHierachy() calls method printParent() is surely an implementation detail of method printHierachy(), and so should not be tested for. Unit tests should check that a method has the required outputs.
For printing methods, checking the format of the printed output would do. For a method that updates a data-base, check that the data-base contains the expected values. For a method that manipulates a domain-model object in a specified manner, check that the domain object is in the correct state. And so on.
I think the mistake may be conceptual. If Child extends Parent, then the methods of Parent are part of the implementation, i.e. the System Under Test.
If the Parent needs to be mocked independently of the Child, then maybe you should use composition instead of inheritance:
public class Child {
private Parent parent;
public void printHierarchy() {
parent.printParent();
}
// setters/getters
}
Now the Parent is mockable and you can test whether printParent() was called or not.
If the class hierarchy is conceptually correct, then you should not need to test internal implementation details (i.e. that the interface/public method calls some other). You do not care about implementation details.
I use Mockito 1.8.0 so I do not have AnyVararg. Upgrading to later version of Mockito is not on cards from my team at the moment. So please bear with me.
What the class looks like:
public abstract class Parent {
public void someMethod(String a, String b)
{
//.....
}
public void foo(String a, String... b)
{
//.....
}
}
public class Child extends Parent{
public void bar() {
someMethod(a,b);
foo(a,b,c);
methodToFailUsingSpy();
}
}
Unit tests
#Test
public void someTest() {
private spyOfChild = //initialize here;
doReturn("Something")).when(spyOfChild).methodToFailUsingSpy();
/* Tried using this, but did not help.
doCallRealMethod().when(spyOfChild).foo(anyString());
*/
spyOfChild.bar();
}
Problem -
When the spy sees someMethod(), it calls the real method in the abstract class. But when it sees foo(), it tries to find a matching stubbed method i.e control goes to Mockito's MethodInterceptorFilter, since it is not able to find a mock, it throws java.lang.reflect.InvocationTargetException.
I do not want foo() to be mocked. I want the real method to be called like it happens in someMethod(). Can someone explain if it is because of using method with variable length arguments with a spy?
This is a bug in Mockito.
https://groups.google.com/forum/#!msg/mockito/P_xO5yhoXMY/FBeS4Nf4X9AJ
Your example is quite complicated, to reproduce the problem is very simple:
class SimpleClass {
public String varargsMethod(String... in) {
return null;
}
public void testSpyVarargs() {
SimpleClass sc = Mockito.spy(new SimpleClass());
sc.varargsMethod("a", "b");
}
}
Even this will produce the error you describe, and the workaround suggested in the link doesn't work for me.
Unfortunately to get around this you will need to upgrade Mockito. Changing to version 1.9.5 makes the above run fine, plus you get the varargs matchers as you say (although note that your problem isn't to do with matchers but how Mockito handles spied varargs methods).
I don't think there were too many huge changes between 1.8.0 and 1.9.5, it shouldn't be too painful.
I have the following structure:
class Bar{
....
protected void restore(){
....
}
....
}
This class is extended by Foo as below:
class Foo extends Bar{
....
#Override
public void restore(){ //valid override
super.restore();
....
}
}
In my jUnit test I would like to test that when foo.restore() is called, the super.restore() is called subsequently. Hence, below is my jUnit test method:
class FooTest{
#Tested
Foo _foo;
#Test
void testRestore(final Bar bar){
new Expectations(){{
bar.restore(); times = 1; // Error! bar.restore() not visible
}};
Deencapsulation.invoke(_foo,"restore");
}
}
Unfortunately, my test cannot compile. The reason is that 1) the restore() of the parent is protected and 2) FooTest and Foo exist together in a separate project (and therefore folder) vs. Bar.
Is there anyway to achieve the desired test? I have checked the jMockit tutorials (many times over the past few months) and have not seen a similar test (same goes for a search on Google).
Update
With the help of the responses, I understand that enforcing subclasses to invoke super is not the best practice, yet this is not my implementation and I still have to test it. I am still looking for a way to enforce my jUnit test to check if the call to the parent is taking place.
So basically you are trying to enforce a contract of calling the super and trying to allow for subclassing? I think that this is not easily done due to the dynamic dispatch that will hide the behavior in Java. I don't think that Mocking will catch this.
A way the ensure that the super is called would be to break out the super and the extension into 2 methods like
class Foo {
public final void restore() {
//parent code...
doRestore();
}
protected void doRestore() {
//empty base implementation
}
}
class Bar extends Foo {
protected void doRestore() {
//do my subclass specific restore stuff here
}
}
The following test should work:
public class FooTest
{
#Tested Foo _foo;
#Test
void restoreInFooCallsSuper(#Mocked final Bar bar)
{
new Expectations() {{
invoke(bar, "restore");
}};
_foo.restore();
}
}
The super.restore() is supposed to do something useful no? some specific logic. In your test simply test that the outcome of invoking the super.restore() happened.
Another way to look into it is the following. In the subclass before doing anything you implement an assert that ensures that the super did its job correctly. This is a stronger check and is well known as part of Meyer's Design by Contract paradigm. In this context the subclass simply checks that the post-condition of the super.restore() implementation holds before executing and by using assert you know it will fail during Unit Tests but also during test integration runs of your application e.g.
class Foo extends Bar{
....
#Override
public void restore(){ //valid override
super.restore();
assert super_restore_worked_ok_condition : "restore post-condition failed";
....
}
}