risingTide
risingTide

Reputation: 1896

Mockito - thenReturn always returns null object

I'm trying to implement Mockito to test a particular method but the .thenReturn(...) seems to always be returning a null object instead of what I intended:

CUT:

public class TestClassFacade {

  // injected via Spring
  private InterfaceBP bpService;

  public void setBpService(InterfaceBP bpService) {

      this.bpService = bpService;
  }

  public TestVO getTestData(String testString) throws Exception {

    BPRequestVO bpRequestVO = new BPRequestVO();

    bpRequestVO.setGroupNumber(testString) ;
    bpRequestVO.setProductType("ALL") ;           
    bpRequestVO.setProfileType("Required - TEST") ;

    IBPServiceResponse serviceResponse = bpService.getProduct(bpRequestVO);  //PROBLEM

    if (serviceResponse.getMessage().equalsIgnoreCase("BOB")) {

        throw new Exception();

    } else {

        TestVO testVO = new TestVO();
    }

    return testVO;
  }

}

Spring Configuration:

<bean id="testClass" class="com.foo.TestClassFacade">

   <property name="bpService" ref="bpService" />

</bean>

<bean id="bpService" class="class.cloud.BPService" />

Mockito Test Method:

@RunWith(MockitoJUnitRunner.class)
public class BaseTest {

    @Mock BPService mockBPService;
    @InjectMocks TestClassFacade mockTestClassFacade;

    private String testString = null;
    private BPRequestVO someBPRequestVO = new BPRequestVO();
    private IBPServiceResponse invalidServiceResponse = new BPServiceResponse();

    @Test (expected = Exception.class)
    public void getBPData_bobStatusCode_shouldThrowException() throws Exception {

        invalidServiceResponse.setMessage("BOB");

        someBPRequestVO.setGroupNumber(null);
        someBPRequestVO.setProductType("ALL");
        someBPRequestVO.setProfileType("Required - TEST");

        System.out.println("1: " + someBPRequestVO.getGroupNumber());
        System.out.println("2: " + someBPRequestVO.getProductType());
        System.out.println("3: " + someBPRequestVO.getProfileType());
        System.out.println("4: " + someBPRequestVO.getEffectiveDate());

        when(mockBPService.getProduct(someBPRequestVO)).thenReturn(invalidServiceResponse);

        mockTestClassFacade.getTestData(testString);

        verify(mockBPService).getProduct(someBPRequestVO);
    }
}

System output:

1: null
2: ALL
3: Required - TEST
4: null

What's happening here is that when I run the test the serviceResponse object is null on the line in the CUT marked with //PROBLEM above. My desire is to have that object be populated with my "invalidServiceResponse" object from my test method. Judging from the output of my System.out.println's it appears that my bpRequestVO matches my someBPRequestVO in content.

Could some one show me what I'm missing here?

Thanks for your time!

Upvotes: 40

Views: 108984

Answers (7)

Ramesh Thoutam
Ramesh Thoutam

Reputation: 79

My issue was with the instance of the service which is autowired/mockbean had different instance at the Test->given() part and whi lein the execution it had different instance.

This was found by running the test in debug mode and checking each value in the mock stub and execution code. If all the parameters and the mocked instance are same then only the thenReturn() will return the expected value.

In myscenario the mocked instance of the class had multiple implementations and by adding @Qualifier("name") the instance became same in the given() and real execution.

Upvotes: 0

davo
davo

Reputation: 390

My issue was passing null as method arguments doesn't match the when() clause I set up.

e.g.

Car car = mock(Car.class)
when(car.start(anyString()).thenReturn("vroom");
assertEquals("vroom", car.start(null));

This would fail.

assertEquals("vroom", car.start("Now"));

This passes.

Upvotes: 0

markkan
markkan

Reputation: 61

My problem was that mocked services were defined as final.

Upvotes: 6

Shrikant
Shrikant

Reputation: 94

The BPRequestVO Object instance used for mocking is different than Instance used while junit execution.

The best way is to configure any instance of the object while mocking

when(mockBPService.getProduct(someBPRequestVO)).thenReturn(invalidServiceResponse);

Can be updated with

when(mockBPService.getProduct(Mockito.any(BPRequestVO.class))).thenReturn(invalidServiceResponse);

Upvotes: 2

Victor Godoy
Victor Godoy

Reputation: 1692

Instead of creating a equals method in your BPRequestVO class you can create a mock argument with "any(YourObject.class)" like this:

when(mockBPService.getProduct(any(BPRequestVO.class))).thenReturn(invalidServiceResponse);

Upvotes: 28

lewthor
lewthor

Reputation: 434

The instance of BPRequestVO that you use with when() is different than the one used in getTestData().
Unless you override equals(), they will not match.

You should not need to write a custom Matcher if you override equals(). Note the following from the Mockito documentation:

"Custom argument matchers can make the test less readable. Sometimes it's better to implement equals() for arguments that are passed to mocks (Mockito naturally uses equals() for argument matching). This can make the test cleaner."

Upvotes: 24

fge
fge

Reputation: 121712

The problem is in your usage of when().

You submit a reference to a constructed instance; as a result, the mocking will return what you want only if the argument passed to the method is the same reference.

What you want is an argument matcher; something like:

when(mockBPService.getProduct(argThatMatches(someBPRequestVO))
    .thenReturn(whatYouWant);

Of course, it requires that you write the argument matcher!

Note that there is a builtin matcher which can do what you want:

when(mockBPService.getProduct(eq(someBPRequestVO))).thenReturn(whatYouWant);

This matcher of course requires that your BPRequestVO class implements equals() (and hashCode() too)!

Upvotes: 12

Related Questions