0

I know that Mockito doesn't support mocking of local variables, static methods and private methods. Is there any way to get around it.

Like in the case of private methods changing the method from private will do or we could change it to a protected interface so that we could write test scripts. So do we have anything like this for static methods and local variables.

https://github.com/mockito/mockito/wiki/FAQ says the limitations of Mockito. Can any Mockito guru let me if it got any other limitations and how to overcome them I mean by refactoring. Thank you.

Random
  • 909
  • 1
  • 9
  • 14
  • So one of the limitation is that you cannot mock local variables which they missed out in that page and it is not a page specifically for limitations. It is a FAQ page. So yeah I think there is some Mockito guru who could help me. – Random Aug 11 '16 at 14:52
  • What do you mean by mocking "local variables"??? (for static method, one could use [Powermock](https://github.com/jayway/powermock/wiki/MockitoUsage)) –  Aug 11 '16 at 14:55
  • 2
    But mockito is about mocking dependencies and interactions between objects. So either a local variable is assigned a mocked object, than you are clear to go. Or if the local variable is assigned some other value than you shouldn't care, because that's the implementation details your test shouldn't depend upon. – SpaceTrucker Aug 11 '16 at 14:57
  • I don't want to use PowerMock. I want to find a way around. is there any possible way. Thank you @RC. – Random Aug 11 '16 at 14:59
  • @SpaceTrucker I agree with you completely. But the problem is in one of my methods I have a local variable and this variable is initialized with an object. I cannot mock any methods using this object. – Random Aug 11 '16 at 15:23
  • There are no workarounds. You have to remove the static from the method and make you local variable initialized somewhere you can control (for example `theVar = someMethod()` and use a spy to control the behavior of `someMethod`. See also http://stackoverflow.com/questions/21105403/mocking-static-methods-with-mockito?rq=1 –  Aug 11 '16 at 15:38

2 Answers2

1

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

Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
  • 1
    Downvoted for promoting "design for mocking", which to me means throwing good design out of the window. – Rogério Aug 11 '16 at 19:31
  • 1
    @Rogério It's important to understand that "design for mocking" is just a specific example of "designing for use with alternative implementations", because alternative test-friendly implementations are exactly what mocking frameworks are designed to provide. As soon as you realize that a test is a first-class consumer of the library you create, then you realize that good design requires accounting for tests, not ignoring them arbitrarily and then hacking around your willful ignorance. – Jeff Bowman Aug 11 '16 at 19:41
  • No, mocking "frameworks" (BTW, they are just "libraries") are not meant to provide "test-friendly implementations". Rather, they provide "mocking", which is a way to replace the "real" implementation of some dependency (which may be empty) with a "mock" implementation, whose exact behavior is specified by a test and by the defaults chosen by the mocking library. The client of these mocked dependencies is not the test, but the class under test. That is, you design the interface of said dependencies according to the needs of its production code clients, not the needs of tests. – Rogério Aug 11 '16 at 20:54
1

The best way to avoid the limitations of Mockito is to not insist on writing isolated unit tests.

Contrary to what some think, unit tests do not need to run in isolation from the dependencies of the tested unit. As described by Martin Fowler (and as practiced by Kent Beck, the "father" of TDD), unit tests can be "sociable" (with no mocking of dependencies) or "solitary" (with mocked dependencies).

So, one way to avoid those mocking tool limitations is to simply not rely on them. You can do that by writing "sociable" unit tests, or (like I do) go the whole way and write integration tests.

The other "solution" that was mentioned is to refactor the code under test in order to work around mocking limitations, or to "design for mocking" (as Jeff Bowman said). I hope most developers realize this is a bad solution, as it usually requires adding extra complexity to the SUT, just to make up for arbitrary limitations in a particular mocking library. Consider the case of increasing the accessibility of a private method so you can test it directly or mock it. Well, if you find that acceptable, do you really care about code quality? And if you don't care, then why bother with automated developer testing anyway?

Rogério
  • 16,171
  • 2
  • 50
  • 63
  • Likewise downvoted; what this answer calls "complexity" is more-aptly flexibility driven by a permanent and key consumer (the test). Ultimately reasonable people can (and do) disagree about is whether it is better design to tightly encapsulate your class and then hack your way through your own walls, or recognize the flexibility your class needs and design for it; this answer treats it as pure black-and-white about "special-case your tests or you might as well throw code quality and testing out the window", which is an unnecessary and false dichotomy. – Jeff Bowman Aug 11 '16 at 19:49
  • @JeffBowman What you call "flexibility" I call over-engineering. For example, there is no good reason to create a Java interface if you only ever expect it to have one implementing class. Or to introduce a factory or DI container when you don't need to select between multiple implementations through external configuration. Consider: why does Mockito supports class mocking? By your point of view (defended by early mock library developers, and still defended by Jon Skeet), developers should only mock interfaces, not classes. But this idea was rejected by most, including Mockito's developers. – Rogério Aug 11 '16 at 21:06
  • @JeffBowman Another point you may be missing is that, if a developer wants *both* code quality and testing, he/she would have to avoid tools like Mockito or EasyMock, as they do not provide proper support for either good design *or* testing. For example, judicious use of `final` is important in API design (see Bloch's "Effective Java"), but is not supported by those tools. If you wanted (for API design reasons) to make a class/method final, you would be unable to mock it. Not that mocking it would be a good idea - I would favor an integration test - but it should still be an option. – Rogério Aug 11 '16 at 21:18
  • "If you wanted (for API design reasons) to make a class/method final, you would be unable to mock it."—and this is correct and important! `final` is a promise to both compiler and developer about exactly which implementation you get. Mocking in that case would _subvert both developer and compiler expectations_, which sounds to me like the _antithesis_ of good design. In any case, I've updated my answer to clarify my message, and further discussion should probably be moved to chat. – Jeff Bowman Aug 11 '16 at 21:25
  • @JeffBowman You confuse implementation details of Mockito's approach to mocking with the concept. As I said before, mocking is a way to "imitate" the behavior of a given dependency, without actually executing its real implementation (if it even has one). Whether that dependency is an `interface`, an `abstract` class, or a `final` class is irrelevant, from the point of view of the test. Good design *requires* the developer to have the freedom to make decisions such as making a class `final`, or instantiating a stateful object with `new`; the limitations of Mockito's approach deny that freedom. – Rogério Aug 12 '16 at 15:58