1

I have simple spring boot application with Controller,Service,Business and Util classes, so I'm trying to mock the method in MockUtil bean which takes four parameters but it returns null

MockMainController

@RestController
public class MockMainController {

@Autowired
private MockBusiness mockBusiness;

@GetMapping("request")
public MockOutput mockRequest() {
    return mockBusiness.businessLogic(new MockInput());

    }

 }

MockBusiness

@Service
public class MockBusiness {

@Autowired
private MockService mockService;

public MockOutput businessLogic(MockInput input) {
    return mockService.serviceLogic(input);
    }

 }

MockService

@Service
public class MockService {

@Autowired
private MockUtil mockUtil;

public MockOutput serviceLogic(MockInput input) {

    ResponseEntity<MockOutput> res = mockUtil.exchange(UriComponentsBuilder.fromUriString(" "), HttpMethod.GET,
            HttpEntity.EMPTY, new ParameterizedTypeReference<MockOutput>() {
            });
    return res.getBody();

    }

 }

MockUtil

@Component
public class MockUtil {

@Autowired
private RestTemplate restTemplate;

public <T> ResponseEntity<T> exchange(UriComponentsBuilder uri, HttpMethod method, HttpEntity<?> entity,
        ParameterizedTypeReference<T> typeReference) {

    try {

        ResponseEntity<T> response = restTemplate.exchange(uri.toUriString(), method, entity, typeReference);

        return response;
    } catch (HttpStatusCodeException ex) {
        System.out.println(ex);
        return new ResponseEntity<T>(ex.getStatusCode());
    } catch (Exception ex) {
        ex.printStackTrace();
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
         }
     }

 }

Below is my simple test class, when ever mockUtil.exchange method is called i want to return object based on ParameterizedTypeReference<T>

MockControllerTest

@SpringBootTest
@ActiveProfiles("test")
@Profile("test")
@RunWith(SpringRunner.class)
public class MockControllerTest {

@Autowired
private MockMainController mockMainController;

@MockBean
private MockUtil mockUtil;

@Test
public void controllerTest() {

    given(this.mockUtil.exchange(ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.any(),
            ArgumentMatchers.any(new ParameterizedTypeReference<MockOutput>() {
            }.getClass()))).willReturn(ResponseEntity.ok().body(new MockOutput("hello", "success")));

    MockOutput output = mockMainController.mockRequest();
    System.out.println(output);

    }

 }

By debugging I can see that mockUtil.exchange is returning null

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
app
  • 733
  • 5
  • 15
  • 27
  • Your entire code setup would probably be simpler if you used constructor injection; you would be able to limit the interaction size substantially. (Note also that `RestOperations` exists specifically as a testing facility.) – chrylis -cautiouslyoptimistic- Mar 06 '19 at 16:42
  • I'm just practicing with all the approaches, can you guide me please how to mock `RestOperation` in place of `RestTemplate` @chrylis – app Mar 06 '19 at 16:44

1 Answers1

3

It seems that the way you match ParameterizedTypeReference is not working. It does not match as you expect.

Try the following:

given(mockUtil
    .exchange(
        ArgumentMatchers.any(),
        ArgumentMatchers.any(),
        ArgumentMatchers.any(),
        // eq matches to any param of the same generic type
        ArgumentMatchers.eq(new ParameterizedTypeReference<MockOutput>(){})))
.willReturn(ResponseEntity.ok().body(new MockOutput("hello", "success")));

It seems after few tests that if you do not use eq Mockito expects the passed ParameterizedTypeReference to be the same instance as in given(..) and with eq it just checks that it represents the same generic type.

Check this question for more details.

pirho
  • 11,565
  • 12
  • 43
  • 70
  • @app Test it yet better before accepting / upvoting. It might be that it just returns null that passes the ANY. So I mean check that it really sees the `ParameterizedTypeReference` by testing it not only with MockOutput but also some other used output and see if you can return different answer with `willReturn` per type. – pirho Mar 06 '19 at 17:34
  • ya you are right I have issue with different type, it is always returning the same type for any type – app Mar 06 '19 at 17:42
  • @app np. try the version with `eq`. – pirho Mar 06 '19 at 17:46