Over a million developers have joined DZone.
Platinum Partner

@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

Discover how AppDynamics steps in to upgrade your performance game and prevent your enterprise from these top 10 Java performance problems, brought to you in partnership with AppDynamics.

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.

The Java Zone is brought to you in partnership with AppDynamics. AppDynamics helps you gain the fundamentals behind application performance, and implement best practices so you can proactively analyze and act on performance problems as they arise, and more specifically with your Java applications. Start a Free Trial.

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

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

{{ parent.tldr }}

{{ parent.urlSource.name }}