简体   繁体   中英

Mockito mocking super class calls

Base class

class BaseSplitter{
    public int splitSalaryHalf(String personName,int Salary){
        //check if person is employee
        //check is person eligible
        //some more check if yes
        //split salary into salary/2 else return -1
        return salary/2 or -1
    }
    public int abc(){
    }
}

Derived class

class Bonus extends BaseSplitter{
    public int giveBonous(String personName,int salary){
        int bonusamount = super.splitsalaryHalf("Sunil",super.splitSalary("Sunil",salary));
        if(bonusamount == -1){
            return 0;
        }
        return Salary + bonusamount
    }
}

I am trying to test giveBonus function with mockito but failing

public class Bonus {

    @Test
    public void giveBonous() throws Exception{
        GiveBonus bonus = Mockito.spy(new Bonus);
        doReturn(500).when((BaseSplitter)Bonus).splitSalaryHalf("sunil",2000);
        int num = bonus.giveBonus("sunil",2000);
        assertEqual(2500,num);
    }
}

Question # 1

The issue is that mockito is not mocking the superclass( splitHalfSalary ) call rather start calling it in real ( splitSalaryHalf function which contains some complex object{not included to keep it simple} ). How can i mock superclass method.

Question # 2

Not applying a composition as I need abc() and other functions in the derived class. Am I applying wrong pattern if Yes? how should I handle the same?

Diagnosing this is made harder because the code you pasted above isn't the real code. For example, the test expects "sunil" but the actual code uses "Sunil". This illustrates the importance of copying the exact code and pasting into your question.

I think the actual answer has to do with the use of the super keyword. If you remove the super keyword from the code example it will work as intended.

Mockito is creating something similar to a dynamic proxy of the original object and wrapping it when you create a spy. The real object is still there and the call to giveBonous() is delegated to the real object by the spy proxy.

The real object makes a call to super.splitSalaryHalf which in Java says, do not call this object's override of splitSalaryHalf -- go directly to the super class's definition of this method and invoke that.

The spy gives you the ability to mock out methods on the wrapped object (Bonus.splitSalaryHalf) but will not replace the super classes implementation.

Mockito's behavior is entirely appropriate because a common pattern would be to override the super class implementation in the subclass, but still have the ability to call the super class's implementation. Consider this:

public class BonusCalculator {
  private double bonusFactor = 0.10;

  public int giveBonus(Employee employee) {
    return employee.getSalary() * bonusFactor;
  }
}

public class AuditableBonusCalculator extends BonusCalculator {
  public int giveBonus(String name, int salary) {
    int bonus = super.giveBonus(name, salary);
    updatePayrollAudit(employee, bonus);
    return bonus;
  }
}

The superclass, BonusCalculator, calculates the actual bonus amount.

The subclass, AuditableBonusCalculator, delegates to the superclass to get the actual bonus amount, but adds the responsibility of updating the payroll audit system to show that the bonus was paid.

Mockito only wraps the subclass with a proxy and can only intercept calls on that specific class. You can still mock methods implemented by the superclass as long as the call is dispatched through the proxy, which it will if the super keyword is not present. But if you use the super keyword, Java explicitly does not consider the current object's implementation, it will go find the superclass's implementation of that method and call it explicitly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM