2

In this situation?

class A {
  public void f() {
    B b = new B();
    C c = new C();
    // use b and c, and how to modify their behaviour?
  }
}

How can I fullfill my idea with PowerMock and EasyMock?

I don't want to change my compact code for test reasons.

Andremoniy
  • 34,031
  • 20
  • 135
  • 241
kimi
  • 123
  • 3
  • 6

4 Answers4

4

You can, in fact, mock object construction using PowerMock. They have great documentation for it right here: https://code.google.com/p/powermock/wiki/MockConstructor

Also take a look at this example which walks through mocking object construction.

Matt Lachman
  • 4,541
  • 3
  • 30
  • 40
  • 1
    +1 Sure I see you can. But that does not mean we should do it. Just making a point. – Narendra Pathai Apr 10 '13 at 05:38
  • 2
    @Narendra The OP said "I don't want to change my compact code for test reasons", which seems to me a perfectly good reason to do it. Instead, you seem to suggest that simple code that works fine should be made more complex just to avoid the use of a mocking tool... – Rogério Apr 10 '13 at 15:21
  • many simple codes that work fine are not good for testing. And making code testable does not make it complex. It saves you time and future redesign. Using this powermock hack is not a good way to do this and MUST only be done when the code that is creating the instance is not in our control i.e belongs to a library or so. – Narendra Pathai Apr 11 '13 at 05:32
  • 2
    I disagree that the only time to use this approach is when the code is not in our control. There are times in software development when _the schedule_ is not in our control and having _any_ test is better than none. If I had to stop and refactor all code so it was "test-friendly" before I could wrap it in unit tests I might never get any tests written. – Matt Lachman Apr 11 '13 at 19:15
  • @MattLachman - How do I make it work when the class that is being used for object creaiton is final. I get the error : "Cannot subclass final class" – bschandramohan Apr 02 '15 at 07:22
  • @ChandraMohan https://code.google.com/p/powermock/wiki/MockFinal – Matt Lachman Apr 08 '15 at 19:22
1

You can do this, see the answer by Matt Lachman. That approach isn't recommended however. It's a bit hacky.

The best approach would be to delegate creation of your dependant objects to a factory pattern and inject the factories into your A class:

class BFactory {

    public B newInstance() {
        return new B();
    }
}

class CFactory {

    public C newInstance() {
        return new C();
    }
}

class A {

    private final BFactory bFactory;
    private final CFactory cFactory;

    public A(final BFactory bFactory, final CFactory cFactory) {
        this.bFactory = bFactory;
        this.cFactory = cFactory;
    }

    public void f() {
        B b = bFactory.newInstance();
        C c = cFactory.newInstance();
    }
}

You would then mock the factories to return mock instances of the dependent classes.

If for some reason this is not viable then your can create factory methods in the A class

class A {

    public void f() {
        B b = newB();
        C c = newC();
    }

    protected B newB() {
        return new B();
    }

    protected C newC() {
        return newC();
    }
}

Then you can use a spy that mocks those factory methods.

Boris the Spider
  • 59,842
  • 6
  • 106
  • 166
0

Looks like you need Dependency Injection.

You are creating concrete instances of B and C, then you cannot modify the behavior.

Pass the instances as an argument to f(InterfaceB b, InterfaceC c), you should make use of polymorphism and then you can pass a mock instance whose behavior you need to change as an argument to this method. So the method does not need to care which type of concrete instance it being passed to it and you can achieve what you need.

I know the names of interfaces are illogical but that could explain the context easily.

Narendra Pathai
  • 41,187
  • 18
  • 82
  • 120
  • @user988722 Did you get what I was targeting to explain? – Narendra Pathai Apr 09 '13 at 07:21
  • I think I got:1. I am not able to fulfill my idea without code changes. 2. I have to re-factor my code to let B and C passed in. right? – kimi Apr 09 '13 at 07:25
  • Yes! It is similar to the factory solutions given. The difference is you are not passing factory but using polymorphism to achieve what you want without creating any new classes. – Narendra Pathai Apr 09 '13 at 08:14
0

Whitout changing the code it will not work. (Design for testability). You can replace B with a factory method, that creates B1 in real, or BTest in test, both implementing IB Interface.

AlexWien
  • 28,470
  • 6
  • 53
  • 83