Mockito 模拟对象被忽略并调用实际函数
Mockito Mock object being ignored and actual function being called
模拟对象似乎不起作用,正在调用实际函数。
我的控制器Class如下:-
@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());
}
}
我的ClassB如下:-
@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;
}
}
这是我的测试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));
}
}
如果你注意到我在 Class B 中创建了 class C 的静态变量。这是程序结构本身的一部分,无法更改。
是否可以根据此代码模拟 client.search
函数?
解决问题的一种快速方法是直接模拟 B
和存根 B.getAns
。
为了模拟静态 B,您应该将 mockito-inline
依赖项添加到 pom.xml:
<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
通过 运行 在调试模式下的测试,我能够找出问题所在。
我发现我的 Class B 中的 @PostConstruct
函数在我的测试函数之前被调用。所以 class B 正在创建自己的 beanClient
对象,这与我的测试 class 中的模拟不同。这就是为什么它进入函数而不是模拟它的原因。
我能够通过像这样更改 Class 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;
}
我不得不将其更改为 non-static 函数。
模拟对象似乎不起作用,正在调用实际函数。
我的控制器Class如下:-
@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());
}
}
我的ClassB如下:-
@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;
}
}
这是我的测试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));
}
}
如果你注意到我在 Class B 中创建了 class C 的静态变量。这是程序结构本身的一部分,无法更改。
是否可以根据此代码模拟 client.search
函数?
解决问题的一种快速方法是直接模拟 B
和存根 B.getAns
。
为了模拟静态 B,您应该将 mockito-inline
依赖项添加到 pom.xml:
<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
通过 运行 在调试模式下的测试,我能够找出问题所在。
我发现我的 Class B 中的 @PostConstruct
函数在我的测试函数之前被调用。所以 class B 正在创建自己的 beanClient
对象,这与我的测试 class 中的模拟不同。这就是为什么它进入函数而不是模拟它的原因。
我能够通过像这样更改 Class 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;
}
我不得不将其更改为 non-static 函数。