Using PowerMock to Mock Constructors

In my opinion, one of the main benefits of dependency injection is that you can inject mock and/or stub objects into your code in order to improve testability, increase test coverage and write better and more meaningful tests. There are those times, however, when you come across some legacy code that doesn’t use dependency injection and held together by composition rather than aggregation.

When this happens, you have three options:

  1. Ignore the problem and not write any tests.
  2. Refactor like mad, changing everything to use dependency injection.
  3. Use PowerMock to mock constructors

Obviously, option 1 isn’t a serious option, and although I’d recommend refactoring to move everything over to dependency injection, that takes time and you have to be pragmatic. That’s where PowerMock comes in… this blog demonstrates how to use PowerMock to mock a constructor, which means that when your code calls new it doesn’t create a real object, it creates a mock object.

To demonstrate this idea, the first thing we need is some classes to test, which are shown below.

public class AnyOldClass {
 
  public String someMethod() {
    return "someMethod";
  }
  
}
public class UsesNewToInstantiateClass {

  public String createThing() {

    AnyOldClass myclass = new AnyOldClass();

    String returnValue = myclass.someMethod();
    return returnValue;
   
  }
  
}

The first class, AnyOldClass, is the class that the code instantiates by calling new. In this example, as the name suggests, it can be anything.

The second class, the aptly named UsesNewToInstantiateClass, has one method, createThing(), which when called does a:

AnyOldClass myclass = new AnyOldClass();

This is all pretty straight forward, so we’ll move quickly on to the PowerMock assisted JUnit test:

import static org.easymock.EasyMock.expect;
import static org.junit.Assert.assertEquals;
import static org.powermock.api.easymock.PowerMock.expectNew;
import static org.powermock.api.easymock.PowerMock.replay;
import static org.powermock.api.easymock.PowerMock.verify;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.annotation.Mock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(UsesNewToInstantiateClass.class)
public class MockConstructorTest {

  @Mock
  private AnyOldClass anyClass;

  private UsesNewToInstantiateClass instance;

  @Test
  public final void testMockConstructor() throws Exception {

    instance = new UsesNewToInstantiateClass();

    expectNew(AnyOldClass.class).andReturn(anyClass);

    final String expected = "MY_OTHER_RESULT";
    expect(anyClass.someMethod()).andReturn(expected);

    replay(AnyOldClass.class, anyClass);
    String result = instance.createThing();
    verify(AnyOldClass.class, anyClass);
    assertEquals(expected, result);
   
  }

}

Firstly, this class has the usual PowerMock additions of:

@RunWith(PowerMockRunner.class)
@PrepareForTest(UsesNewToInstantiateClass.class)

at the top of the file plus the creation of the anyOldClass mock object. The important line of code to consider is:

expectNew(AnyOldClass.class).andReturn(anyClass);

This line of code tells PowerMock to expect a call to new AnyOldClass() and return our anyClass mock object.

Also of interest are the calls to replay and verify. In the example above, they both have two arguments. The first, AnyOldClass.class relates to the expectNew(…) call above, whilst the second, anyClass refers to the straight forward mock call expect(anyClass.someMethod()).andReturn(expected);.

There are those times when you should really let new do what it does: create a new object of the requested type. There is a body of opinion that says you can over-isolate your code when testing and that mocking everything reduces the meaning and value of a test. To me there’s no right answer to this and it’s a matter of choice.

It’s fairly obvious that if your code accesses an external resource such as a database, then you’d either refactor and implement DI or use PowerMock. If your code under test doesn’t access any external resources, then it’s more of a judgement call on how much code isolation is too much? This perhaps needs some thought and may be the subject for another blog on anther day…

Reference: Using PowerMock to Mock Constructors from our JCG partner Roger Hughes at “Captain Debug’s” Blog.

Related Whitepaper:

Bulletproof Java Code: A Practical Strategy for Developing Functional, Reliable, and Secure Java Code

Use Java? If you do, you know that Java software can be used to drive application logic of Web services or Web applications. Perhaps you use it for desktop applications? Or, embedded devices? Whatever your use of Java code, functional errors are the enemy!

To combat this enemy, your team might already perform functional testing. Even so, you're taking significant risks if you have not yet implemented a comprehensive team-wide quality management strategy. Such a strategy alleviates reliability, security, and performance problems to ensure that your code is free of functionality errors.Read this article to learn about this simple four-step strategy that is proven to make Java code more reliable, more secure, and easier to maintain.

Get it Now!  

Leave a Reply


6 + = twelve



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close