To help understand Mockito's limitations, it's important to realize what Mockito is doing for you: Mockito creates a dynamic (proxy-based) subclass of the class you pass in. This means that, like a subclass you would write yourself, you won't have access or control over private fields and methods, static methods, and local variables. There is no workaround.
You mentioned PowerMock in the comments, which works around some of the Mockito limitations by rewriting the bytecode of the class you want to mock, or the class that consumes a class you want to mock. This allows PowerMock to intercept calls that you can't override via polymorphism, particularly private
, static
, and final
fields. You also won't have access to local variables.
Your best bet is, instead, to restructure your class or method so that it does give you the control you want. In general you should be asking "would I be able to do this if I created my own subclass", and that answer will help determine whether Mockito can automate it for you.
(Note that below I've referred to "designed for mocking", but what you're really doing is designing for alternative implementations of your dependencies; mocks are just one example of this, along with a variety of other test doubles like fake or in-memory implementations. Remember that not everything needs to be mocked or substituted for your test to remain a unit test; just make sure your dependencies in tests are fast, deterministic, and well-tested. Conversely, for slow, nondeterministic, poorly-tested, or yet-unwritten components, substituting an implementation with a fake or mock may improve test quality and coverage.)
public class NotDesignedForMocking {
public int yourMethod() {
Calculator calculator = new Calculator(); // impossible to mock!
return calculator.calculate();
}
}
One technique is to pass in your dependency as a method parameter.
public class DesignedForMockingViaMethodLevelDependencyInjection {
public int yourMethod() {
return yourMethod(new Calculator());
}
// Call this from tests instead; you can pass in a mock.
int yourMethod(Calculator calculator) {
return calculator.calculate();
}
}
Another is to switch to full dependency injection:
public class DesignedForMockingViaFullDependencyInjection {
private final Calculator calculator;
public DesignedForMockingViaFullDependencyInjection() {
this(new Calculator());
}
// Create objects in your test with this, so you can pass in a mock Calculator.
DesignedForMockingViaFullDependencyInjection(Calculator calculator) {
this.calculator = calculator;
}
int yourMethod() {
return calculator.calculate();
}
}
Finally, you can create an overridable factory method, which introduces the polymorphism that Mockito needs for its subclass-based overrides.
public class DesignedForMockingWithOverridableFactoryMethod {
public int yourMethod() {
Calculator calculator = createCalculator();
return calculator.calculate();
}
// Create an anonymous override in your class, or use a Mockito spy to intercept
// and override the behavior.
protected Calculator createCalculator() {
return new Calculator();
}
}
See also: How to use Mockito when we cannot pass a mock object to an instance of a class