3

I have a class A which instantiates an object from class B internally. That second class has lots of external side-effects, e.g. it uses a network connection.

public class A {
  private B b;
  public A() {
    b = new B(); // 3rd party class that calls out externally (e.g. to a db)
  }
}

I would like to unit test class A by providing a mock implementation of class B. I can easily create a mocked version of B by writing my own class or using something like Mockito and other frameworks, but how do I inject this mock implementation into class A's code?

I guess I could ask for an instance of class B in class A's constructor, but that seems ugly. No one really needs to know how class A does it's business.

Python has a "mock" library that allows you to "patch" functions at run time during a test. Does Java have something similar?

oneself
  • 38,641
  • 34
  • 96
  • 120
  • possible duplicate of [What's the best mock framework for Java?](http://stackoverflow.com/questions/22697/whats-the-best-mock-framework-for-java) – Chris Dennett Sep 30 '12 at 20:57
  • In my experience, the easiest way to create a "mock object" is to just: 1) Create a new .java file with the same class/filename, 2) copy/paste all the public methods, 3) add the bare minimum needed to "do something", and 4) modify my project so the build will pick up the new, "mock" class instead of the "real" class. IMHO... – paulsm4 Sep 30 '12 at 21:02
  • 1
    A common solution to this is "dependency injection". Basically this means you avoid doing "b = new B();" in your constructors precisely to preserve "testability". Instead you *always* have the objects you need provided from the outside. This means there's no difference between using a real or a mock object as far as `A` is concerned. – millimoose Sep 30 '12 at 21:04
  • Good links: [The Concept of Mocking](http://www.michaelminella.com/testing/the-concept-of-mocking.html), and [Testing with EasyMock](http://www.vogella.com/articles/EasyMock/article.html) – paulsm4 Sep 30 '12 at 21:06

3 Answers3

3

In this scenario I typically have a 2nd package (default) scope constuctor that allows you to pass a mock in for testing purposes.

public class A {
  private B b;

  /*
  *  Used by clients
  */
  public A() {
    this(new B());
  }

  /*
  * Used by unit test
  * 
  * @param b A mock implementation of B
  */
  A(B b) {
    this.b = b;
  }
}
Martin
  • 7,089
  • 3
  • 28
  • 43
  • I think that this is probably the best compromise without employing something like Spring. I'm going to see if I can use DI to fix this more correctly. – oneself Oct 01 '12 at 14:33
0

Check out Mockito. Ultimately, based on your design, you'll need to use reflection to get the mock instance of B into A.

Chris Thompson
  • 35,167
  • 12
  • 80
  • 109
0

This is trivial to solve with the JMockit mocking API:

public class ATest
{
    @Test
    public void myTest(@Mocked B mockB)
    {
        // Record expectations on "mockB", if needed.

        new A().doSomethingUsingB();

        // Verify expectations on "mockB", if applicable.
    }
}
Rogério
  • 16,171
  • 2
  • 50
  • 63
  • Will this mock class B's constructor? If not, then this is not what the original question is asking for. – oneself Apr 26 '13 at 21:35
  • Yes, it will. All constructors and methods (including `static`, `final`, `private`, etc.) in the `@Mocked` class *are* mocked. – Rogério Apr 27 '13 at 13:18