How to mock local variables in java? [duplicate]

2019-07-15 16:32发布

问题:

This question already has an answer here:

  • Mocking methods of local scope objects with Mockito 5 answers

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.

回答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.



回答2:

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.



回答3:

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.



回答4:

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.