Over a million developers have joined DZone.

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

Unfortunately, I have seen it misused several times when a better design would be the solution.

· Java Zone

What every Java engineer should know about microservices: Reactive Microservices Architecture.  Brought to you in partnership with Lightbend.

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.

Microservices for Java, explained. Revitalize your legacy systems (and your career) with Reactive Microservices Architecture, a free O'Reilly book. Brought to you in partnership with Lightbend.

Topics:
java,spring,dependency injection,tips and tricks,unit test,bad practice

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}