Calling method with mock issue

855 views
Skip to first unread message

Anjib Mulepati

unread,
Aug 21, 2014, 11:23:08 PM8/21/14
to moc...@googlegroups.com
//My Test Class
@Before
   public void setup() {
       reset(mockOpenCaseService);
       mockMvc = MockMvcBuilders.standaloneSetup(openCaseController).build();
       
        List<OpenCaseDto> value = new ArrayList<OpenCaseDto>();
       OpenCaseDto openCase = new OpenCaseDto();
       openCase.setResultCount(20L);
       value.add(openCase);
       
        when(mockOpenCaseService.getOpenCases(providerId, firmId, page, pageLength, columnSortInfo)).thenReturn(value); // this 'value' has one element
   }

@Test
   public void getOpenCases() throws Exception {
       mockMvc.perform(get("/cases/openCases.htm")
               .param("start", "0")
               .param("length", "20")
               .param("draw", "0"))
           .andExpect(status().isOk())
           .andExpect(content().contentType(new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"))));
   }

//My Controller method
@RequestMapping
(value = "/cases/openCases.htm", method = RequestMethod.GET)
   public @ResponseBody DataTablesResponse<OpenCaseDto> getOpenCases(Model model, HttpServletRequest request) {
   ......    
    try {
           openCases = openCaseService.getOpenCases(providerId, firmId, page, pageLength, columnSortInfo); //this return empty openCases
   
}
   
....


I am using mockito to mock one of the service call in my controller. In test setup my data structure is set properly and I am telling test to return this value when controller service is called. But when I run a test in controller it is empty. 
Isn't that when getOpenCases() is called mockito will return setup value? Help me understand this.

Eric Lefevre-Ardant

unread,
Aug 22, 2014, 5:24:52 AM8/22/14
to moc...@googlegroups.com
Well, Mockito returns the setup value only when it can verify that all parameters are equal to the ones in the setup.

So, it will actually call the .equals() method on the following values: providerId, firmId, page, pageLength, and columnSortInfo (of course, if the pointers are the same, then it works too).
It is not clear from your snippet if that would work for each of the parameter. Try providing a valid equals() method for each of the types involved and let us know how it goes.


--
You received this message because you are subscribed to the Google Groups "mockito" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mockito+u...@googlegroups.com.
To post to this group, send email to moc...@googlegroups.com.
Visit this group at http://groups.google.com/group/mockito.
For more options, visit https://groups.google.com/d/optout.

Anjib Mulepati

unread,
Aug 22, 2014, 10:22:16 AM8/22/14
to moc...@googlegroups.com
Yes it seems columnSortInfo data is mismatch. I am using private method in controller to create this object from the request parameter.
List<ColumnOrder> columnsDetail = extractSortOrderParam(request);
List<ColumnSortInfo> columnSortInfo = createSortInfo(columnsDetail);

I did set columnSortInfo in setup() method of test class but still not working
ColumnSortInfo sortInfo = new ColumnSortInfo();
sortInfo
.setColumnName("CASE_OPEN_DATE");
sortInfo
.setColumnSortOrder("desc");
columnSortInfo
.add(sortInfo);

Now my question is
1) is there a way to tell mockito to mock columnSortInfo and pass to getOpenCases(0 method and return openCases as real data doesn't matter in this case?
2) If not then is that in ColumnSortInfo  I have to write .equal() and hashCode() method?

Note:
I changed
@Mock List<ColumnSortInfo> columnSortInfo;
to
List<ColumnSortInfo> columnSortInfo = new ArrayList<ColumnSortInfo>();

and initialize in setup()



On Friday, August 22, 2014 4:24:52 AM UTC-5, Eric Lefevre-Ardant wrote:
Well, Mockito returns the setup value only when it can verify that all parameters are equal to the ones in the setup.

So, it will actually call the .equals() method on the following values: providerId, firmId, page, pageLength, and columnSortInfo (of course, if the pointers are the same, then it works too).
It is not clear from your snippet if that would work for each of the parameter. Try providing a valid equals() method for each of the types involved and let us know how it goes.
On 22 August 2014 05:23, Anjib Mulepati <anji...@gmail.com> wrote:
//My Test Class
@Before
   public void setup() {
       reset(mockOpenCaseService);
       mockMvc = MockMvcBuilders.standaloneSetup(openCaseController).build();
       
        List<OpenCaseDto> value = new ArrayList<OpenCaseDto>();
       OpenCaseDto openCase = new OpenCaseDto();
       openCase.setResultCount(20L);
       value.add(openCase);
       
        when(mockOpenCaseService.getOpenCases(providerId, firmId, page, pageLength, columnSortInfo)).thenReturn(value); // this 'value' has one element
   }


@Test
   public void getOpenCases() throws Exception {
       mockMvc.perform(get("/cases/openCases.htm")
               .param("start", "0")
               <code style="font-family:Consolas,'Bitstream Vera Sans Mono','Courier New',Courier,monospace!important;line-height:1.1em!important;border-top-left-radius:0px!important;border-top-right-radius:0px!important;border-bottom-right-radius:0px!important;border-bottom-left-radius:0px!important;float:none!important;min-height:auto!important;out
...

Eric Lefevre-Ardant

unread,
Aug 22, 2014, 10:37:57 AM8/22/14
to moc...@googlegroups.com
On 22 August 2014 16:22, Anjib Mulepati <anji...@gmail.com> wrote:
1) is there a way to tell mockito to mock columnSortInfo

No, not if it is instantiated inside your class under test.
 
and pass to getOpenCases(0 method and return openCases as real data doesn't matter in this case?

Not sure I understand what you are saying.
It *is* possible to tell Mockito to ignore the value of a parameter, though. Something like this:
  when(mockOpenCaseService.getOpenCases(eq(providerId), eq(firmId), eq(page), eq(pageLength), any(ColumnSortInfo.class))).thenReturn(value);
 
2) If not then is that in ColumnSortInfo  I have to write .equal() and hashCode() method?

That's what I would recommend.

Anjib Mulepati

unread,
Aug 22, 2014, 11:23:24 AM8/22/14
to moc...@googlegroups.com
Now I am using
when(mockOpenCaseService.getOpenCasesany(any(Long.class), any(Long.class),  any(Integer.class), any(Integer.class), any(List.class)).thenReturn(openCases));
to call
List<ColumnSortInfo> columnSortInfo = createSortInfo(columnsDetail);

openCases
= openCaseService.getOpenCases(providerId, firmId, page, pageLength, columnSortInfo);    

but getting error for last parameter. How to set any() for such list type?

Eric Lefevre-Ardant

unread,
Aug 22, 2014, 11:51:37 AM8/22/14
to moc...@googlegroups.com
Try anyList() or anyListOf()


--

Anjib Mulepati

unread,
Aug 22, 2014, 11:54:55 AM8/22/14
to moc...@googlegroups.com
I replace when with
Mockito.doReturn(openCases).when(mockOpenCaseService).getOpenCases(providerId, firmId, page, pageLength, columnSortInfo);

but test is failing with 406 error. When I did .andDo(print())
it shows
Resolved Exception:
                Type = org.springframework.web.HttpMediaTypeNotAcceptableException
Since my controller methos is returing ResponseBodyType do I have to do any type setting or other?



--
You received this message because you are subscribed to a topic in the Google Groups "mockito" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/mockito/pPu-KOMtMHo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to mockito+u...@googlegroups.com.

KARR, DAVID

unread,
Aug 22, 2014, 12:43:24 PM8/22/14
to moc...@googlegroups.com

What error are you getting?  Is it a compile error or a runtime error?

 

--

Anjib Mulepati

unread,
Aug 22, 2014, 1:07:33 PM8/22/14
to moc...@googlegroups.com
Its runtime error. Test is failing with error
java.lang.AssertionError: Status expected:<200> but was:<406>

I have my mockMvc setup as

@Test
    public void getOpenCases() throws Exception {
        mockMvc.perform(get("/cases/openCases.htm")
                .accept(MediaType.APPLICATION_JSON)

                .param("start", "0")
                .param("length", "20")
                .param("draw", "0")
                .param("order[0][column]", "4")
                .param("order[0][dir]", "desc")
                )
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON));
    }

andDo(print()) showing following information
MockHttpServletRequest:
                Headers = {Accept=[application/json]}


Resolved Exception:
                Type = org.springframework.web.HttpMediaTypeNotAcceptableException

MockHttpServletResponse:
              Status = 406
       Error message = null
             Headers = {}
        Content type = null
                Body =
       Forwarded URL = null
      Redirected URL = null
             Cookies = []





--
You received this message because you are subscribed to a topic in the Google Groups "mockito" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/mockito/pPu-KOMtMHo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to mockito+u...@googlegroups.com.

Marcin Grzejszczak

unread,
Aug 22, 2014, 1:17:04 PM8/22/14
to moc...@googlegroups.com

Hi

Most likely it could be issue concerning threads. Mockito operates on ThreadLocal and most likely your mocked service looses the stubbing info when a request arrives. Thats a hypothesis though.

Btw why and are you mocking a service that is your Spring bean?

Anjib Mulepati

unread,
Aug 22, 2014, 1:49:42 PM8/22/14
to moc...@googlegroups.com
I didn't exactly get you question but if you are asking why I mock OpenCaseService I am doing unit testing not and integration test for just a controller and testing its response (which is a JSON string)

Marcin Grzejszczak

unread,
Aug 22, 2014, 1:57:21 PM8/22/14
to moc...@googlegroups.com

Maybe i've misunderstood some of your code cause I just took a glance and didn't have time to look at what you're writing thouroughly but if you're unit testing then why do you need Spring context set up?

If you're unit testing then why do you even need a mockMvc since you could just instantiate your controller, inject mocks and execute the method that you're testing?

Anjib Mulepati

unread,
Aug 22, 2014, 1:58:52 PM8/22/14
to moc...@googlegroups.com
I am new on this .. could you provide an example

Marcin Grzejszczak

unread,
Aug 22, 2014, 2:01:35 PM8/22/14
to moc...@googlegroups.com

Can you please show your whole test class?

Also could you exactly state what's the purpose of this test and what do you want to achieve?

Anjib Mulepati

unread,
Aug 22, 2014, 3:21:31 PM8/22/14
to moc...@googlegroups.com
Here is what I am trying to achieve. I have bunch of controllers and services. Services use repos to get data from the DB. I want to start with unit test for each layer starting with controller. So my first attempt is to test controller to see if it return JSON string in my case as I am not returning the view.

So for my controller test  I am trying to send param and expecting the JSON response string. I think second step will be to verify the JSON string content (not sure if this be unit or integration test?). Then I will write unit test for each layer then move to integration test.

Here is my test class with aim to get success response and some JSON string.

@RunWith(MockitoJUnitRunner.class)
public class OpenCaseControllerTest {
    MockMvc mockMvc;
   
    //Services used in controller
    @Mock OpenCaseService mockOpenCaseService;
    @Mock ProviderService mockProviderService;
    @Mock DomainMemberService mockDomainMemberService;

    //Objects used in controller at various step
    @Mock Provider provider;
    @Mock Individual individual;
    @Mock ProviderFunctions providerFunctions;
    @Mock Organization organization;
   
    @InjectMocks OpenCaseController openCaseController = new OpenCaseController();
   
    //Values need for the request method
    Long providerId = 12345L;
    Long firmId = 67890L;
    Integer page = 1;
    Integer pageLength = 20;

    List<ColumnSortInfo> columnSortInfo = new ArrayList<ColumnSortInfo>();

    //Return from service method
    List<OpenCaseDto> openCases = new ArrayList<OpenCaseDto>();
   
   
    @Before
    public void setup() {
        reset(mockProviderService, mockOpenCaseService, mockDomainMemberService);
        mockMvc = MockMvcBuilders.standaloneSetup(openCaseController).build();
       
        //this service call return provideId
        when(mockProviderService.getLoggedInProvider()).thenReturn(provider);
        when(provider.getId()).thenReturn(providerId);
       
        //this service return firmId
        when(mockDomainMemberService.getMember(providerId)).thenReturn(individual);
        when(individual.asProvider()).thenReturn(providerFunctions);
        when(providerFunctions.getFirm()).thenReturn(organization);
        when(organization.getId()).thenReturn(firmId);
       
        //created dummy openCase

        OpenCaseDto openCase = new OpenCaseDto();
        openCase.setResultCount(20L);
        openCases.add(openCase);
       
        //created dummy col sort info
        ColumnSortInfo sortInfo = new ColumnSortInfo();
        sortInfo.setColumnName("CASE_OPEN_DATE");
        sortInfo.setColumnSortOrder("desc");
        columnSortInfo.add(sortInfo);
       
        //mock for service call
        Mockito.doReturn(openCases).when(mockOpenCaseService).getOpenCases(providerId, firmId, page, pageLength, columnSortInfo);
    }
   
    @Test
    public void getOpenCases() throws Exception {
        mockMvc.perform(get("/cases/openCases.htm")
                .accept(MediaType.APPLICATION_JSON)
                .param("start", "0")
                .param("length", "20")
                .param("draw", "0")
                .param("order[0][column]", "4")
                .param("order[0][dir]", "desc")
                )
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON));
    }

}

Thanks

Marcin Grzejszczak

unread,
Aug 22, 2014, 5:37:00 PM8/22/14
to moc...@googlegroups.com

Would it also be able to see your sut? I'm asking cause your test seems to be really complex so either you've made your test overcomplicated or maybe your controller does too much?

KARR, DAVID

unread,
Aug 22, 2014, 7:37:22 PM8/22/14
to moc...@googlegroups.com

Typically, a “unit test” of a service controller would not use HTTP to contact the controller.  It would simply instantiate the controller and inject dependencies (Marcin basically said the same thing).  What you have here is more of an integration test, as you’re really testing the REST infrastructure, not just your business logic.  This is a good thing to do, but it’s not a unit test, and you shouldn’t run it as a unit test.  It will run much slower than a unit test, and as unit tests should run as part of your regular build, that will be a drain on developers.

 

If you were to write a true unit test for your controller, you would look at the business logic of the controller and determine what in it is “critical business logic” and write your test to verify that functionality.  In my experience, REST service controllers typically don’t have much logic in them, as they usually delegate most of their work to the transactional service layer.  If that’s the case for you, I wouldn’t bother too much with unit tests for that layer.

Russell Bateman

unread,
Aug 23, 2014, 11:14:09 AM8/23/14
to moc...@googlegroups.com
David (and everyone else on this thread and in this forum),

I remember years ago when I struggled with these concepts. Your recent answer here, and many like it in this forum, are (and were) invaluable to us. I can't thank you enough.

I would point out also, perhaps, some other great tools that have helped me, in chronological order of acquisition:

Steve Freeman, Growing Object-oriented Software, Guided by Tests
Tomek Kaczanowski, Practical Unit Testing with TestNG/JUnit and Mockito
Marcin, Grzejszczak, Mockito Cookbook

For me Mockito has been a godsend and this forum is one of the best and most helpful I've had the pleasure to haunt.

Russ

Marcin Grzejszczak

unread,
Aug 23, 2014, 2:01:18 PM8/23/14
to moc...@googlegroups.com

I totally agree with David.

If I was to start implementing this solution via tdd I would start with writing a smoke integration fest of a controller that would return a simple OK response. Then I would start the red green reactor approach.

Next I would start writing test cases bit by bit of my functionality and write unit tests for the created collaborators where it makes sense.

Marcin Grzejszczak

unread,
Aug 23, 2014, 2:02:07 PM8/23/14
to moc...@googlegroups.com

Hi Russell

I'm really happy that my book helped you with your work :)

--

Anjib Mulepati

unread,
Aug 25, 2014, 6:34:39 AM8/25/14
to moc...@googlegroups.com
My SUT
@Controller
public class OpenCaseController {
    @Autowired ProviderService providerService;
    @Autowired OpenCaseService openCaseService;
    @Autowired DomainMemberService domainMemberService;
     
    @RequestMapping(value = "/cases/openCases.htm", method = RequestMethod.GET)
    public @ResponseBody DataTablesResponse<OpenCaseDto> getOpenCases(Model model, HttpServletRequest request) {
        Long providerId = providerService.getLoggedInProvider().getId();
        Long firmId = domainMemberService.getMember(providerId).asProvider().getFirm().getId();
        Integer startIndex = Integer.parseInt(request.getParameter("start"));
        Integer pageLength = Integer.parseInt(request.getParameter("length"));
        Integer page = startIndex/pageLength + 1;
        DataTablesResponse<OpenCaseDto> response = new DataTablesResponse<OpenCaseDto>();
        List<OpenCaseDto> openCases = new ArrayList<OpenCaseDto>();
        List<ColumnOrder> columnsDetail = extractSortOrderParam(request);
        List<ColumnSortInfo> columnSortInfo = createSortInfo(columnsDetail);
        try {
            openCases = openCaseService.getOpenCases(providerId, firmId, page, pageLength, columnSortInfo); //this is empty    
            Integer totalRecordFiltered = openCases.get(0).getResultCount().intValue();
            response.setRecordsTotal(totalRecordFiltered);
            response.setRecordsFiltered(totalRecordFiltered);
            response.setData(openCases);
            response.setError(null);
        } catch(Exception e) {
            response.setRecordsTotal(0);
            response.setRecordsFiltered(0);
            response.setData(openCases);
            response.setError("DB Error" + e.getMessage());
        }
        response.setDraw(Integer.parseInt(request.getParameter("draw")));
         
        return response;
    }


--
You received this message because you are subscribed to a topic in the Google Groups "mockito" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/mockito/pPu-KOMtMHo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to mockito+u...@googlegroups.com.

Marcin Grzejszczak

unread,
Aug 25, 2014, 7:00:40 AM8/25/14
to moc...@googlegroups.com
Hi Anjib!

I don't have much time to go through all of this code but if I was to do a code review of this what caught my eye at first glance was:

Violation of Single Responsibility principle - there are far too many things going on

Refactoring proposal:
1) Injection via constructor
2) You're passing result form providerService to domainMemberService. Then you're passing it to openCaseService - maybe extract this logic to a separate component and make Controller profit from its results instead of calling all of them directly
3) You want to test if response is proper? Do not create the response directly in Controller - extract it to a separate component and unit test that component. Why should controller even handle any exceptions? Why not make a dedicated component do that for the controller.
4) Instead of passing to openCaseService params like providerId, firmId, page, pageLength, columnSortInfo you could pass a meaningful structure (object).

I wish I could do a more detailed code review but I don't have too much time.

I wouldn't unit test this controller - I would create an integration test, set up the application context and use mockMvc to check if for given input I got an expected output to prove that as a whole - this part of my application is operaitonal.

Pozdrawiam / Best regards,
Marcin Grzejszczak
Senior software developer
Reply all
Reply to author
Forward
0 new messages