Mockito Mock对象被忽略,实际函数被调用

pftdvrlh  于 2022-11-08  发布在  其他
关注(0)|答案(2)|浏览(199)

模拟对象似乎不起作用,正在调用实际函数。
我的控制器类如下:-

@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());
    }

}

我的B类如下:-

@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;
    }
}

这是我的测试类:

@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));

    }
}

如果你注意到我已经在我的类B中创建了一个类C的静态变量,这是程序结构本身的一部分,不能改变。
在给定这段代码的情况下,是否可以模拟client.search函数?

tmb3ates

tmb3ates1#

我能够通过在调试模式下运行测试来找出问题所在。
我发现类B中的@PostConstruct函数在我的测试函数之前被调用。所以类B创建了自己的beanClient对象,与我的测试类中的mock不同。这就是为什么它进入函数而不是mock它的原因。
我能够解决它通过改变类B如下:-

@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;
 }

我不得不将其更改为非静态函数。

ozxc1zmp

ozxc1zmp2#

解决问题的一个快速方法是直接模拟B和存根B.getAns
为了模拟静态B,应该在pom.xml中添加mockito-inline依赖项:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>3.8.0</version>
    <scope>test</scope>
</dependency>

可以按以下方式使用Mockito.mockStatic

try (MockedStatic<B> mockedB = Mockito.mockStatic(B.class)) {
    mockedB.when(() -> B.getAns(anyString())).thenReturn(obj);
    // ...
}

因此,您的测试代码将是:

@Test(enabled = true)
public void testing() throws Exception {
    try (MockedStatic<B> mockedB = Mockito.mockStatic(B.class)) {
        JSONObject obj = new JSONObject() // assume this object is not null
        mockedB.when(() -> B.getAns(anyString())).thenReturn(obj);

        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));
    }
}

请注意,当您使用MockedStatic时,最好使用try-with-resources模式,并在此范围内进行如上所述的测试。
了解有关mockStatic的更多信息:https://www.baeldung.com/mockito-mock-static-methods

相关问题