Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using PowerMock or How much do you let your tests affect your design? [closed]

I've been a fan of EasyMock for many years now, and thanks to SO I came across references to PowerMock and it's ability to mock Constructors and static methods, both of which cause problems when retrofitting tests to a legacy codebase.

Obviously one of the huge benefits of unit testing (and TDD) is the way it leads to (forces?) a much cleaner design, and it seems to me that the introduction of PowerMock may detract from that. I would see this mostly manifesting itself as:

  1. Going back to initialising collaborators rather than injecting them
  2. Using statics rather than making the method be owned by a collaborator

In addition to this, something doesn't quite sit right with me about my code being bytecode manipulated for the test. I can't really give a concrete reason for this, just that it makes me feel a little uneasy as it's just for the test and not for production.

At my current gig we're really pushing for the unit tests as a way for people to improve their coding practices and it feels like introducing PowerMock into the equation may let people skip that step somewhat and so I'm loathe to start using it. Having said that, I can really see where making use of it can cut down on the amount of refactoring that needs to be done to start testing a class.

I guess my question is, what are peoples experiences of using PowerMock (or any other similar library) for these features, would you make use of them and how much overall do you want your tests influencing your design?

like image 445
tddmonkey Avatar asked Jan 09 '09 11:01

tddmonkey


People also ask

When should I use PowerMock?

The main aim of PowerMock is to extend the existing APIs with some methods and annotations to provide extra features that make unit testing quite easy. The PowerMock framework provides a class called PowerMockito used to create mock objects and initiates verification and expectation.

Is PowerMock needed?

Typically, clean code won't need powermock for testing. Because clean code supports dependency injection, is loosely coupled and is easy to unit test so doesn't rely on static methods.

What is the difference between PowerMock and Mockito?

While Mockito can help with test case writing, there are certain things it cannot do viz:. mocking or testing private, final or static methods. That is where, PowerMockito comes to the rescue. PowerMockito is capable of testing private, final or static methods as it makes use of Java Reflection API.

Can you use Mockito and PowerMock together?

Of course you can – and probably will – use Mockito and PowerMock in the same JUnit test at some point of time.


1 Answers

I have to strongly disagree with this question.

There is no justification for a mocking tool that limits design choices. It's not just static methods that are ruled out by EasyMock, EasyMock Class Extension, jMock, Mockito, and others. These tools also prevent you from declaring classes and methods final, and that alone is a very bad thing. (If you need one authoritative source that defends the use of final for classes and methods, see the "Effective Java" book, or watch this presentation from the author.)

And "initialising collaborators rather than injecting them" often is the best design, in my experience. If you decompose a class that solves some complex problem by creating helper classes that are instantiated from that class, you can take advantage of the ability to safely pass specific data to those child objects, while at the same time hiding them from client code (which provided the full data used in the high-level operation). Exposing such helper classes in the public API violates the principle of information hiding, breaking encapsulation and increasing the complexity of client code.

The abuse of DI leads to stateless objects which really should be stateful because they will almost always operate on data that is specific to the business operation. This is not only true for non-public helper classes, but also for public "business service" classes called from UI/presentation objects. Such service classes are usually internal code (to a single business application) that is inherently not reusable and have only a few clients (often only one) because such code is by nature domain/use-case specific. In such a case (a very common one, by the way) it makes much more sense to have the UI class directly instantiate the business service class, passing data provided by the user through a constructor.

Being able to easily write unit tests for code like this is precisely what led me to create the JMockit toolkit. I wasn't thinking about legacy code, but about simplicity and economy of design. The results I achieved so far convinced me that testability really is a function of two variables: the maintainability of production code, and the limitations of the mocking tool used to test that code. So, if you remove all limitations from the mocking tool, what do you get?

like image 200
Rogério Avatar answered Nov 10 '22 01:11

Rogério