Search code examples
unit-testingmockitospring-boot-testmockmvc

Mockito Mock object being ignored and actual function being called


The mock object does not seem to work and the actual function is being called.

My Controller Class is as follows:-

@RestController
public class A {

    @PostMapping(path = "/api/methods", consumes = "application/json", produces = "application/json")
    public static ResponseEntity<Object> controllerFunction(@Valid @RequestBody String request,
        @RequestHeader(value = "header-content") String header_content) {

        JSONObject response = B.getAns(request);
        return ResponseEntity.status(HttpStatus.OK).body(response.toString());
    }

}

My Class B is as follows:-

@Service
public class B {

    private static C client;

    @Autowired
    private C beanClient;

    @PostConstruct
    public void init() {
        B.client = beanClient;
    }

    public static JSONObject getAns(String request) {
        // This is the line that I intend to mock but gets ignored. It goes into the function search instead.

        JSONObject resp = client.search(searchRequest, requestHeaderOptions); // assume that these two variables passed as arguments are not null and have some content.

        // searchRequest is of type SearchRequest
        // requestHeaderOptions is of type RequestOptions
        return resp;
    }
}

This is my test class :

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {
    ControllerApplication.class, A.class, B.class, C.class
})
@ActiveProfiles("test")
public class ProjectTest {

    @Mock
    private C client;

    @InjectMocks
    A a;

    private MockMvc mockMvc;

    @BeforeSuite
    public void setup() {

        // I have tried both MockitoAnnotations.initMocks and openMocks. Both don't work
        MockitoAnnotations.openMocks(this);
        this.mockMvc = MockMvcBuilders.standaloneSetup(a).build();

    }

    @Test(enabled = true)
    public void testing() throws Exception {

        JSONObject obj = new JSONObject() // assume this object is not null

        // This statement doesn't seem to work
        doReturn(obj).when(client).search(any(SearchRequest.Class), any(RequestOptions.Class));

        MockHttpServletRequestBuilder mockRequest = MockMvcRequestBuilders.post("/api/methods")
            .contentType(MediaType.APPLICATION_JSON)
            .accept(MediaType.APPLICATION_JSON)
            .header("header-content", "something")
            .content("someData");

        mockMvc.perform(mockRequest)
            .andExpect(content().contentType(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(content().json(jsonResponse));

    }
}

If you notice I have created a static variable of the class C in my Class B. This is part of the program structure itself and cannot be changed.

Is it possible to mock the client.search function given this code?


Solution

  • I was able to figure out what the problem was by running the test in debug mode.

    I found that the @PostConstruct function in my Class B was getting called before my test function. So class B was creating its own beanClient object different from the mock in my test class. That's why it was going into the function and not mocking it.

    I was able to resolve it by changing Class B like so:-

    @Service
    public class B{
     
     @Autowired
     private C client;
    
     public  JSONObject getAns(String request){
         // This is the line that I intend to mock but gets ignored. It goes into the function search instead.
    
         JSONObject resp =client.search(searchRequest,requestHeaderOptions); // assume that these two variables passed as arguments are not null and have some content.
         
         // searchRequest is of type SearchRequest
         // requestHeaderOptions is of type RequestOptions
         return resp;
     }
    

    I had to change it into a non-static function.