2

How do I mock my CustomLogger and LogUtil to get my test to pass? I have already mocked them in my test class but it looks like it doesn't count.

Please refer to my 2 comments starting with 'TEST (1 and 2)'. If I uncomment BOTH of them, the test passes.

It looks like the mocking is recognised upon reaching the controller but further down when other classes are called, it no longer counts.

// TEST CLASS

@InjectMocks
private MyController controller;

@Mock
private LogUtil logUtil;

@Mock
private CustomLogger logger;

@Mock
private ConfigurationService configService;

private MockMvc mockMvc;

@Test
public void testMyException() throws Exception {
    when(configService.getConfiguration(anyString()))
            .thenThrow(new ConfigurationException(""));

    mockMvc.perform(
            get("/api/some/bad").accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isBadRequest())
            .andExpect(content().string(""))
            .andExpect(
                    status().reason(
                            "Invalid parameter in Request"));
}

//CONTROLLER CLASS

@Autowired
ConfigurationService configService;

@Autowired
private CustomLogger logger;

@RequestMapping(value = "api/some/{argument}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody
SomeConfiguration getAllInfo(@PathVariable String argument,
        HttpServletRequest request, HttpServletResponse response) {
    try {
        SomeConfiguration configuration = configService.getConfiguration(argument);
        logger.doSomething();
        return configuration;
    } catch (ConfigurationException e) {
        logger.doSomething(); // no issue here
        throw new CustomException("config error", e); // after reaching here, we go to ControllerAdvice's badRequestErrorHandler
    }
}

//ADVICE MANAGING EXCEPTIONS

@ControllerAdvice
public class GlobalExceptionHandlingControllerAdvice {

   @Autowired
   private LogUtil logUtil;

   @Autowired
   private CustomLogger logger;

   @ExceptionHandler(CustomException.class)
   @ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "Invalid parameter in Request")
   public void badRequestErrorHandler(HttpServletRequest request, HttpServletResponse response) {
     // LogUtil logUtil = new LogUtil(); // TEST Will pass if I uncomment this (1)
     logUtil.logFail(request, "BAD REQUEST"); 
   }
}

//LOG UTIL CLASS

@Component
public class LogUtil {
  @Autowired
  private CustomLogger logger;

  public void logFail(HttpServletRequest request, String errorMsg){
    // CustomLogger logger = new CustomLoggerImpl(); // TEST Will pass if I uncomment this (2)
    logger.doLogging();
  }
}

EDIT: Tried adding following into my test method which makes no difference.

private GlobalExceptionHandlingControllerAdvice advice = new GlobalExceptionHandlingControllerAdvice ();
doNothing().when(logUtil).logFail(any(HttpServletRequest.class), anyString());
doNothing().when(logger).setFieldValue(anyString(), anyString());
doNothing().when(advice).badRequestErrorHandler(any(HttpServletRequest.class), any(HttpServletResponse.class));
kang
  • 707
  • 4
  • 17
  • You may want to check out the `OutputCapture` rule, https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-output-capture-test-utility – Darren Forsythe Oct 03 '18 at 16:51
  • @DarrenForsythe That doesn't answer my query. I am looking to mock a method within a class called in the Controller. – kang Oct 03 '18 at 23:15
  • Edited the question to add something I tried which makes no difference unfortunately. – kang Oct 03 '18 at 23:16
  • Are you using Spring-Test? Eg. @RunWith (SpringRunner.class) ? – Roddy of the Frozen Peas Oct 03 '18 at 23:19
  • @RoddyoftheFrozenPeas I am using Power Mock - @RunWith(PowerMockRunner.class) – kang Oct 04 '18 at 08:38
  • My point is why instead of mocking just let the logging run and use the rule to verify it? POwermock is a terrible solution for this it is not what it was designed for. – Darren Forsythe Oct 04 '18 at 09:36
  • @DarrenForsythe Problem is that the logging is not running. When I reach GlobalExceptionHandlingControllerAdvice, the Autowired seems to be not working for LogUtil logUtil; Its value shows as null. I can't just run the log. I need to find a solution around making the test recognising logUtil inside GlobalExceptionHandlingControllerAdvice, thus trying to mock it. I will handle tests for logging separately. Right now, I just want 'testMyException' test to pass. – kang Oct 04 '18 at 10:02
  • Where do you call `MockitoAnnotations.initMocks(this)` ? – Roddy of the Frozen Peas Oct 04 '18 at 15:06

1 Answers1

0

Are you try with:

//CONTROLLER CLASS

@Autowired
ConfigurationService configService;

@Autowired
private CustomLogger logger;

Use @Autowired instead of @Mock here.

But i think the better is: How to test a controller with constructor injection by MockMvc


EDIT: In the setup method, you add the below code:

GlobalExceptionHandlingControllerAdvice advice = new GlobalExceptionHandlingControllerAdvice ();

WhiteBox.setInternalState(advice , "logUtil", logUtil);
WhiteBox.setInternalState(advice , "logger", logger);

mockMvc.setControllerAdvice(advice);

Hope it will help you.