Mock a superclass constructor
Asked Answered
S

3

5

I would like to know if I can mock a super class constructors call and its super() calls.

For example, I have the following classes

class A
{
    A(..)
    {
        super(..)
    }
}   

class B extends A
{
    B(C c)
    {
        super(c)
    }
}

So, I am planning to unit test some methods in class B, but when creating an instance it does call the super class constructors making it tough to write unit tests. So, how can I mock all the super class constructor calls. Also I would like to mock few methods in class A so that it does return few values as I need.

Thanks!!

Selfloading answered 2/5, 2012 at 20:41 Comment(4)
What exactly is making it hard to test B? The fact that it calls superclass constructors isn't inherently problematic. You should be trying to mock dependencies, not behaviour of the object itself.Chader
I discuss suppressing ctors using PowerMock with EasyMock in this blog post, I don't have a Mockito version. It's not clear if you want to eliminate the ctor or replace it, though.Pneuma
@Jon Skeet. yes I do understand that but in order to achieve that it's lot complex and starts multiple threads in the background invoking many external dependencies which aren't needed for my unit test.Selfloading
Then you should be injecting those dependencies, not creating them in the superconstructor. That's the point.Legendary
B
2

You could use PowerMock library. It is really a lifesaver when you need to accomplish things like yours. https://github.com/powermock/powermock/wiki/Suppress-Unwanted-Behavior

Bracey answered 3/5, 2012 at 6:37 Comment(1)
I wasn't aware of that part of the PowerMock library. I still think it points to a "smell" but just because something stinks doesn't mean you have the ability to actually clean it.Avouch
L
2

Mocking a constructor is a very bad idea. Doing so is circumventing behavior that will happen in production. This is why doing work in the constructor, such as starting threads and invoking external dependencies, is a design flaw.

Can you honestly say that the work performed in the constructor has no effect on the behavior you're trying to test? If the answer is no, you run the risk of writing a test that will pass in a test environment, but fail in production. If the answer is yes, that is a plain case for moving that "work" outside the constructor. Another alternative is to move the behavior you're trying to test to another class (maybe it's own).

This is even more true if you're using a DI framework like Guice (which I assume because you tagged it that way).

Legumin answered 3/5, 2012 at 22:53 Comment(0)
A
0

The short answer to your question is "not exactly." You can't 'mock' a constructor, let alone a super. Also mocking super.anyMethod is difficult or impossible with mocking frameworks I'm familiar with. Powermock does allow you to suppress super constructors and problematic methods, which isn't quite the same as mocking them, but could help.

When B extends A, it is of course completely coupled with A. That's not a problem per se but it can be and it looks like it is here. Instead of having B extend A, try having B contain an A instead (and perhaps implement the same interface if necessary). Then you can inject a mock A and delegate all of the calls that you want. That would be much easier to unit test, no?

It's one of the benefits of test driven development that you discover these things in your design during testing.

Avouch answered 3/5, 2012 at 3:41 Comment(1)
See above re: PowerMock. Regardless of whether it's a good idea or not, replacing a constructor at runtime is possible.Ironbark

© 2022 - 2024 — McMap. All rights reserved.