I was born in Cuba, and live in Argentina since January 2009. I'm a self-learned software developer and currently I'm working with the NetBeans IDE and platform. I've also participated in NetCAT68, NetCAT69, NetCAT70, NetCAT71, NetCAT72, NetCAT73 and NetCAT74. I am currently Java back-ender Software Developer at Globant Rosario. Almost obsessed to code quality; I can be annoying in this subject. Alied has posted 10 posts at DZone. You can read more from them at their website. View Full User Profile

@Autowired + PowerMock: Fixing Some Spring Framework Misuse/Abuse

11.19.2013
| 4957 views |
  • submit to reddit

Every time I see PowerMock as a test dependency I tend to get nervous. Don't get me wrong; PowerMock is a great library and does great work. I just have a problem with people who abuse it. I don't doubt there are many scenarios where it will be very useful; however, I have yet to actually find one in my Real World(TM) job. Unfortunately, I have seen it misused several times when a better design would be the solution.

One way I have seen it used is with Spring @Autowired in private fields. Of all ways to use Spring DI, this is the worst. You cannot properly test; you depend on Spring to fully populate your class, and you cannot reuse your class without carrying the whole Spring framework.

I was once working on a project with lots of classes like this:

public class Client {
  @Autowired
  private Service service;

  public void doSomething() {
    service.doServiceStuff();
  }

}
Being private fields, there is no correct way to set them outside Spring. You will need to use Reflection or some sort of black magic.

The developers opted to use PowerMock:
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Client.class })
public class ClientTest {

  @InjectMocks
  private Client client= new Client();
  @Mock
  private Service service;

  @Test
  public void doSomethingTest {
    //setup test data
    client.doSomething();
  }
}

They decided to add a new dependency and make the code even more complicated. I then refactored it like this:

public class Client {

  private Service service;

 @Autowired
 public Client(final Service service) {
    //check preconditions
    this.service = service;
  }

  public void doSomething() {
    service.doServiceStuff();
  }
}

Now it is clear what this class depends on, and you cannot instantiate it (directly or indirectly) without the required dependencies (you will appreciate this when you have some nasty NPEs in production because someone added a new @Autowired private field). Not to mention we got rid of an unneeded dependency.

And the test looked like this:

@RunWith(MockitoJUnitRunner.class)
public class ClientTest {

  @Mock
  private Service service;

  @Test
  public void doSomethingTest {
    //setup test data
    final Client client= new Client(service);
    client.doSomething();
    //assertions and verifications
  }
}

It is unfortunate that frameworks like Spring, otherwise very useful, are so easily misused (should I say abused?) by people who don't take the time to analyze the problem at hand. Maybe a good framework should not be that powerful? Or maybe going the not preferred way should be tedious and effort consuming? I would like to know your opinions about this.

Soon I'll be posting more magic with PowerMock to fix a bad design.

Published at DZone with permission of its author, Alied Pérez.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)