nervosol
nervosol

Reputation: 1291

Is it possible to invoke mocked object's method?

I have, for example, this class:

public class A {
    private List<String> list;

    public A(B b){
        list = b.getList();
    }

    public List<String> someMethod(){
        return list;
    }
}

I want to unit test someMethod without invoking constructor. I use reflection to set list.

The problem is that I don't want to create B class object and I cannot mock it since it will cause NPE.

So my question is:

How to test someMethod without calling constructor of A? Is there any way to mock class A and doesn't lose posibility to call methods?

Creating constructor with zero arguments is not a solution.

Note: I don't want to change any part of A class. I'm asking if it is possible to perform this test without adding or changing anything in A class.

Upvotes: 3

Views: 4562

Answers (3)

Tatera
Tatera

Reputation: 448

You can test class A without calling it's constructor by Mockito. Not sure if I really understand your requirement but the following codes work for me.

import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;

import java.util.ArrayList;
import java.util.List;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class ATest {

    @Test
    public void test() {
        A a = mock(A.class);
        when(a.someMethod()).thenCallRealMethod();
        List<String> listInA = new ArrayList<String>();
        ReflectionTestUtils.setField(a, "list", listInA);
        assertThat(a.someMethod(), is(listInA));
    }
}

Upvotes: 6

Software Engineer
Software Engineer

Reputation: 16140

You should mock out the collaborators to your class -- that means that you can create an instance of the class being tested, and pass in mocks, configured to 'do the right thing' when it's methods are called.

In your example, you want to create a mock B, and use it like this:

@RunWith(MockitoJUnitRunner.class)
class myTest {
  @Mock private B b;

  public void someMethod() {
    doReturn(new ArrayList<String>()).when(b).getList();
    A a = new A(b);
    assertEquals("result", a.someMethod().get(0));
  }
}

Upvotes: 4

Peter Lawrey
Peter Lawrey

Reputation: 533680

I don't want to create B class object

Add a constructor or factory method which doesn't require a B.

public A(B b){
    this(b.getList());
}

/* package local */ A(List<String> list){
    this.list = list;
}

By making the constructor package local it can be accessed by unit tests in the same package.

How to test someMethod without calling constructor of A?

You can use

A a = theUnsafe.allocateInstance(A.class);

but this is not recommended unless you have no other option e.g. deserialization.

Upvotes: -2

Related Questions