开发者

Can I mock a protected superclass method call in Java?

I have stumbled up开发者_如何学运维on a testing problem of mocking a call of protected method from a super class.

e.g. :

public class A extends B {
    @Override
    protected int calculate(int x, int y) {
         int result = super.calculate(x, y);
         result += 10;
         return result;
    } 
}

So is it possible by any means to mock super.calcluate(x,y)? I have tried it with spy but spy could not invoke super method cause it's out of scope I think.


I would imagine a mocking framework would allow for you to mock protected members, but if your mocking framework doesn't, have you considered creating a stub of the class?

public class AStub extends A {
    @Override
    protected int calculate(int x, int y) {
        // do stub calculation 
        return calculation;
    }
}


When you mock an object, you don't care about its implementation. You only add expectations about which method is called.

If you mock A, then your expectations will say something "I expect method calculate on A to be called with parameters 2 and 3, and the result will be 15".

You don't care what the calculate method does in practice, that's the whole point of mocking.


You shouldn't be mocking a call to super. A unit test is intended to test the functionality of a class, and the functionality of ancestor classes is a part of that functionality.

The only time you should need to mock a super class is when the ancestor class behaves badly - such as initializing outside classes as part of its own initialization (without the projection of dependency injection) or accessing external resources (without the projection of dependency injection). If you have access to the ancestor class, refactor it to remove these problems.


Unfortunately, I don't think there's an easy way to mock super.calculate.

I can see that you want to write a "clean" unit test for A that does not rely on B, which is a reasonable aim. But if A is calling a protected method on its superclass, Java makes it hard to decouple the two classes.

This is one of many examples where using inheritance couples classes more closely than you'd like.

Ideally A would wrap B rather than extending it (i.e. using composition rather than inheritance), and would then call myB.calculate rather than super.calculate.

Both classes could implement the same interface (e.g. Calculable) to allow them to be treated polymorphically by clients. This approach would requre B.calculate to be public, or at least package-public. Your unit test could set up an A that wraps a mock B, thereby solving your problem.

I think you have to choose between increasing the visibility of calculate(), as described above, and writing a clean unit test - I don't think you can have both.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜