0

I want to write unit tests for the following class:

public class Target() {

    private final Member member = new Member();

    public Target() {
    } 

}

I want to initialize this Target class with a mocked instance of Member, as it is not feasible to instantiate Member during testing. Is that possible with any framework?

EDIT:

I do not want to mock Target class. I intend to mock Member class at the time of initialization.

Object method() {
    member.differentMethod();
    //Logic which I want to test
}

Please suggest how to mock this call to the method of Member class.

alpha_ulrich
  • 536
  • 5
  • 21
  • Yes your easymock/mocito/powermock framework. But are you just interested in mocking framework or you want to test Target class itself? – SMA Jan 02 '16 at 12:06
  • I wish to test the Target class. However, whenever I try to initialize Target(), I receive an error, as it internally calls Member(), and that requires setting up loads of resources which I want to avoid. I know how to initialize classes with mocked objects using constructors with arguments. But I don't have a clue how to do that in this case. – alpha_ulrich Jan 02 '16 at 12:10
  • Doesnt makes sense but mocking Target class, how are you going to test target class itself? – SMA Jan 02 '16 at 12:11
  • There is some misunderstanding. I do not want to mock the Target class, but the Member class within it. Updated the description. – alpha_ulrich Jan 02 '16 at 12:17
  • Instead of using such an implicit dependency and tight binding, pass the Member object as parameter to the constructor (constructor injection). That way you can pass a mocked Member in your unit test. – Corubba Jan 02 '16 at 12:20
  • Use Reflection to inject mocked version of member... – SMA Jan 02 '16 at 12:40

3 Answers3

2

To build off of Prim's answer (upvoted), just give yourself two constructors.

public class Target() {

  private final Member member;

  public Target() {
    this.member = new Member();
  }

  /** Testing constructor. Package-private visibility for tests in the same package. */
  Target(Member member) {
    this.member = member;
  }    
}

By supplying multiple constructors, you ensure your consumers in production will not have to change at all. This is also a distinct case from "testing code polluting production": One of your use-cases (specifically a test) requires a custom implementation of Member, and you are providing the most-encapsulated access for the replacement of that member as spec'ed.

See also: How to use Mockito when we cannot pass a mock object to an instance of a class

Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
1

You should pass the instance of Member use by Target class into contructor of Target class.

By doing that, you can use the implementation of you Member class in production environment, and use one another implementation (which may be empty) in test environment.

The best and optimal solution is to use Dependency Inversion/Injection principle

Prim
  • 2,880
  • 2
  • 15
  • 29
  • Yes, I am aware of that method. But is there a way to do this without changing the NoArgsConstructor? – alpha_ulrich Jan 02 '16 at 12:18
  • You can use no args constructor in Target, by implementing a provider class which delegates the creation of Member instance and by returning different implementations according to production or test environment – Prim Jan 02 '16 at 12:20
  • Well, I guess I have to somehow change the way the Target class is designed to properly test it. Either by changing the constructor, or having a provider class or factory for initializing Member. Lets see if someone comes up with a solution without essentially requiring changes in the Target class. – alpha_ulrich Jan 02 '16 at 12:24
1

You can use constructor mocking with Powermock:

@RunWith(PowerMockRunner.class)
@PrepareForTest(Target.class)
public class Test {
    @Test
    public void doSomething() throws Exception {
        Member mockMember = mock(Member.class);
        PowerMockito.whenNew(Member.class).thenReturn(mockMember);
        Target thisTargetWillHaveYourMockAsField = new Target();
        //Your test code
    }
}
Gábor Lipták
  • 9,646
  • 2
  • 59
  • 113