user3775713
user3775713

Reputation: 41

How to mock instance inside constructor?

I have a class

public class MockSampleUser {

    private Address address = null;

    public MockSampleUser(){
        address = new Address();
    }

    public String getAddress(){
        return address.getAddress();
    }

    class Address {
        public String getAddress(){
            return "Address";
        }
    }

}

Unit Test:

import static org.junit.Assert.*;
import org.junit.Test;
import static org.mockito.Mockito.*;

public class MockSampleUserTest {

    @Test
    public void MockSampleUser(){

        MockSampleUser.Address address = mock(MockSampleUser.Address.class);
        MockSampleUser mockSampleUser = spy(MockSampleUser.class);

        when(address.getAddress()).thenReturn("New Address");
        String add = mockSampleUser.getAddress();
        assertEquals("New Address", add);

        add = mockSampleUser.getAddress();
        assertEquals("Address", add);
    }
}

I want to write a test, when I call getAddress of class MockSampleUser when it will return "New Address". I want to write a test, when I call getAddress of class MockSampleUser when it will return "New Address".

Upvotes: 1

Views: 1546

Answers (1)

davidxxx
davidxxx

Reputation: 131466

Mocking is designed to mock dependencies of the object under test, not to mock implementation details.
Actually address is not a dependency that the client can set, so you don't have a way to mock it with Mockito.
What you should do is overloading the constructor/change the actual constructor to accept a Address parameter or providing a setter for this field if the dependency is mutable.
For example with constructors :

public MockSampleUser(){
    address = new Address();
}

public MockSampleUser(Address){
    this.address = address;
}

For example with setter :

public void setAddress(Address){
    this.address = address;
}

Note that about your unit test, you want that getAddress() return distinct things as you invoke it multiple time :

String add = mockSampleUser.getAddress();
assertEquals("New Address", add);

add = mockSampleUser.getAddress();
assertEquals("Address", add);

It makes no sense as it references the same object and that its state was not changed between the two assertions.

Your test should rather look like (spy is helpless here and it is right for most of cases) if you don't allow the address dependency to be mutable :

@Test
public void MockSampleUser(){
    MockSampleUser.Address address = mock(MockSampleUser.Address.class);
    MockSampleUser mockSampleUser = new MockSampleUser(address);
    when(address.getAddress()).thenReturn("New Address");

    String add = mockSampleUser.getAddress();
    assertEquals("New Address", add);
    // or better, use the address object itself as expected
    assertEquals(address.getAddress(), add);
}

If you allow the address dependency to be mutable, setter should be favored and there you can assert the before/after state of the object under test:

@Test
public void MockSampleUser(){
    MockSampleUser mockSampleUser = new MockSampleUser();
    // before setting the address
    assertEquals("Address", mockSampleUser.getAddress());

    // after setting the address
    MockSampleUser.Address address = mock(MockSampleUser.Address.class);
    mockSampleUser.setAddress(address);
    when(address.getAddress()).thenReturn("New Address");
    String add = mockSampleUser.getAddress();
    assertEquals("New Address", add);
    // or better, use the address object itself as expected
    assertEquals(address.getAddress(), add);
}

Upvotes: 1

Related Questions