如何模拟服务 class 调用 Rest API 并获取 ResponseEntity 作为响应
How to mock a service class calling Rest API and getting ResponseEntity as Response
我有以下 classes.
@Service
class RestService {
@Autowired
private RestTemplate restTemplate;
public ResponseEntity<String> callService(String param) {
return restTemplate.exchange(....);
}
}
@Service
class CallingService{
@Autowired
private RestService restService;
public ResponseDTO getResponse(String param) {
ResponseEntity<String> response = restService.callService(param);
ResponseDTO responseDTO = convert(response)// JSON Convertor here
return responseDTO;
}
}
现在我想为 CallingService class 编写测试 class。
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import javax.xml.datatype.DatatypeConfigurationException;
import org.apache.cxf.helpers.IOUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.jupiter.api.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@RunWith(MockitoJUnitRunner.class)
@SpringBootTest
class CallingServiceTest{
@InjectMocks
private CallingService service;
@Mock
private RestService restService;
@Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<>("response message", header,
HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}
行 service.getResponse("param") 的调用给出 NullPointerException。在调试时,我发现 CallingService.getResponse() 中收到的响应为空(即 restService.callService(param) 返回空),因此代码分解为 convert() 方法。
我尝试了很多代码操作,但没有成功。希望有人对此有答案。
您不能同时使用 @RunWith(MockitoJUnitRunner.class)
和 @SpringBootTest
。他们都在设置 JUnit 规则,您只能激活一个规则。
您需要使用 Spring 注释。而不是 @Mock
使用 @MockBean
所以 Spring 可以正确地将它注入服务。
@SpringBootTest
class CallingServiceTest{
@Autowired
private CallingService service;
@MockBean
private RestService restService;
@Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<>("response message", header,
HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}
或者,您可以只使用 Mockito,因为我认为您不需要为这个测试初始化 SpringContext。
@RunWith(MockitoJUnitRunner.class)
class CallingServiceTest{
@InjectMocks
private CallingService service;
@Mock
private RestService restService;
@Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<>("response message", header,
HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}
根据您的导入,您正在使用 Junit4
和 Junit5
的组合。
这将无法正常工作。
步骤 运行 Junit5
- 将导入更改为
org.junit.jupiter.api.*
- 将
@Before
更改为 @BeforeEach
。
- 删除
@SpringBootTest
不需要 Junit5
- 将
@RunWith(MockitoJUnitRunner.class)
更改为@ExtendWith(MockitoExtension.class)
请在下面找到更改后的代码
@ExtendWith(MockitoExtension.class)
class CallingServiceTest{
@InjectMocks
private CallingService service;
@Mock
private RestService restService;
@Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<>("response message", header,
HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}
如果您想 运行 和 Junit4
将 @Test
的导入从 import org.junit.jupiter.api.Test
更改为 import org.junit.Test
任何一种解决方案都可以。
我终于找到了结合以上两个答案的变通方法。
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.apache.cxf.helpers.IOUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@RunWith(MockitoJUnitRunner.class)
@SpringBootTest
public class CallingServiceTest{
@InjectMocks
private CallingService service;
@Mock
private RestService restService;
@BeforeEach
public void setup(){
MockitoAnnotations.init(this);
}
@Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<> ("response message", header, HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}
我有以下 classes.
@Service
class RestService {
@Autowired
private RestTemplate restTemplate;
public ResponseEntity<String> callService(String param) {
return restTemplate.exchange(....);
}
}
@Service
class CallingService{
@Autowired
private RestService restService;
public ResponseDTO getResponse(String param) {
ResponseEntity<String> response = restService.callService(param);
ResponseDTO responseDTO = convert(response)// JSON Convertor here
return responseDTO;
}
}
现在我想为 CallingService class 编写测试 class。
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import javax.xml.datatype.DatatypeConfigurationException;
import org.apache.cxf.helpers.IOUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.jupiter.api.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@RunWith(MockitoJUnitRunner.class)
@SpringBootTest
class CallingServiceTest{
@InjectMocks
private CallingService service;
@Mock
private RestService restService;
@Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<>("response message", header,
HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}
行 service.getResponse("param") 的调用给出 NullPointerException。在调试时,我发现 CallingService.getResponse() 中收到的响应为空(即 restService.callService(param) 返回空),因此代码分解为 convert() 方法。
我尝试了很多代码操作,但没有成功。希望有人对此有答案。
您不能同时使用 @RunWith(MockitoJUnitRunner.class)
和 @SpringBootTest
。他们都在设置 JUnit 规则,您只能激活一个规则。
您需要使用 Spring 注释。而不是 @Mock
使用 @MockBean
所以 Spring 可以正确地将它注入服务。
@SpringBootTest
class CallingServiceTest{
@Autowired
private CallingService service;
@MockBean
private RestService restService;
@Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<>("response message", header,
HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}
或者,您可以只使用 Mockito,因为我认为您不需要为这个测试初始化 SpringContext。
@RunWith(MockitoJUnitRunner.class)
class CallingServiceTest{
@InjectMocks
private CallingService service;
@Mock
private RestService restService;
@Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<>("response message", header,
HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}
根据您的导入,您正在使用 Junit4
和 Junit5
的组合。
这将无法正常工作。
步骤 运行 Junit5
- 将导入更改为
org.junit.jupiter.api.*
- 将
@Before
更改为@BeforeEach
。 - 删除
@SpringBootTest
不需要Junit5
- 将
@RunWith(MockitoJUnitRunner.class)
更改为@ExtendWith(MockitoExtension.class)
请在下面找到更改后的代码
@ExtendWith(MockitoExtension.class)
class CallingServiceTest{
@InjectMocks
private CallingService service;
@Mock
private RestService restService;
@Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<>("response message", header,
HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}
如果您想 运行 和 Junit4
将 @Test
的导入从 import org.junit.jupiter.api.Test
import org.junit.Test
任何一种解决方案都可以。
我终于找到了结合以上两个答案的变通方法。
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.apache.cxf.helpers.IOUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@RunWith(MockitoJUnitRunner.class)
@SpringBootTest
public class CallingServiceTest{
@InjectMocks
private CallingService service;
@Mock
private RestService restService;
@BeforeEach
public void setup(){
MockitoAnnotations.init(this);
}
@Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<> ("response message", header, HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}