0

I'm often confronted with the problem of mocking direct instantiations of classes:

final File configFile = new File(pathFile);

I'd like to mock new File(pathFile) in order to make a doReturn(otherFile).

I found that I could mock the direct instantiation by wrapping it in another method. Thing is I don't want to amend all my code by creating methods for instantiations just for unit testing, that would be ugly.

Is there any other way?

Grégoire Borel
  • 1,880
  • 3
  • 33
  • 55

1 Answers1

-1

Under ideal circumstances, your method call is opaque: The only way you can influence it is to change its state, dependencies, or parameters. Constructors are inherently static method calls, which provide no opportunity (in Java) for overriding or adjusting behavior. The constructor might as well be inlined, and on some virtual machines that may literally happen.

Other than creating a testing "seam" for yourself, such as a factory object or overridable method, your only other choice is to edit the bytecode between when the class is compiled and when it is run in your test—which, incidentally, is what PowerMock does as in default locale's comment. Though PowerMock is a powerful and useful library, it does have some extremely specific installation steps that can be tricky to get right, and then you're testing the PowerMock-edited version of your class-under-test rather than the class itself.

See this answer for a related question (how to mock an instance in a private field). The specific outcome is different, but similarly you have to either refactor for testing or break encapsulation.

Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
  • Mocking or wrapping `File` is just a bad idea, even though mocking `File` can actually be done cleanly. The point that "the constructor could be inlined" makes no sense to me; whether it would happen or not is irrelevant. PowerMock does indeed suffer from a few usability issues, but you make it sound as it's much worse than it actually is; AFAIK, lots of Mockito users use it on occasion. The final point about "testing the PowerMock-edited version" sounds like nothing more than FUD to me; I know from experience it's not a real issue. – Rogério Jul 21 '15 at 13:58
  • I'm sorry my answer didn't suit you; my point about PowerMock was merely that "[a good unit test should be as realistic as you can make it](http://stackoverflow.com/a/31076306/1426891)", which you wrote elsewhere, and that there aren't a lot of opportunities other than an "ugly" method (from the question) or a bytecode-level rewrite of a call that otherwise would have been static and unchangeable (Powermock). I didn't think those points were particularly controversial. – Jeff Bowman Jul 21 '15 at 14:56
  • Yes, I favor *integration* tests (with no or minimal mocking) over *unit* tests. So, creating a "seam" *or* mocking `File` are both ugly here; a good test would use real files. Mocking is occasionally needed, though, and then it shouldn't matter if what you need to mock is `static`, a constructor, etc; the mocking tool should do the job that is needed without forcing compromises on the code under test. A real example: I recently wrote integration tests for a Java EE 7 web app where I needed to mock the `FacesContext.getCurrentInstance()` static method. – Rogério Jul 23 '15 at 17:56
  • I'm not advocating for a mock file; the OP wanted to substitute a _different file_, which is pretty common in tests, and (to me) best accomplished by refactoring for that flexibility (i.e. introducing a seam). By all means, PowerMock is the right tool for certain jobs even if I'm not fond of it myself—my mention of it here is just to explain how it works _in order to explain how deeply it has to modify the code to mock without an explicit seam_. – Jeff Bowman Jul 23 '15 at 18:11