如何模拟服务 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
}
}

根据您的导入,您正在使用 Junit4Junit5 的组合。 这将无法正常工作。

步骤 运行 Junit5

  1. 将导入更改为 org.junit.jupiter.api.*
  2. @Before 更改为 @BeforeEach
  3. 删除 @SpringBootTest 不需要 Junit5
  4. @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
}
}