如何在 Java Spring boot 中模拟 RestTemplate?
Posted
技术标签:
【中文标题】如何在 Java Spring boot 中模拟 RestTemplate?【英文标题】:How to mock RestTemplate in Java Spring boot? 【发布时间】:2020-05-01 00:38:53 【问题描述】:我正在尝试使用以下代码模拟 RestTemplate
getEntity()
方法,但我遇到了异常,我是单元测试的新手
谁能帮帮我,我的错误是什么
类
public List<SampleObject1> getGitHubUSersList()
try
ResponseEntity<SampleObject1[]>responseEntity = restTemplate.getForEntity("https://api.github.com/users", SampleObject1[].class);
List<SampleObject1>arrayList = Arrays.asList(responseEntity.getBody());
System.out.println("final list is---->"+objectMapperl.writeValueAsString(arrayList));
return arrayList;
catch (Exception e)
e.printStackTrace();
return null;
测试类
public class SampleServiceTest1
@Mock
RestTemplate mockrestTemplate;
@InjectMocks
@Spy
SampleService1 sampleService;
@Before
public void setup()
MockitoAnnotations.initMocks(this);
@SuppressWarnings("unchecked")
@Test
public void getGitHubUSersListTest()
List<SampleObject1> sampleObject1s = new ArrayList<>();
SampleObject1 sampoleObject1 = new SampleObject1();
sampoleObject1.setId(1);
sampoleObject1.setLogin("sample1");
sampoleObject1.setNode_id("sample2");
sampleObject1s.add(sampoleObject1);
SampleObject1 sampoleObject2 = new SampleObject1();
sampoleObject2.setId(2);
sampoleObject2.setLogin("sample3");
sampoleObject2.setNode_id("sample4");
sampleObject1s.add(sampoleObject2);
Mockito.doReturn(sampleObject1s).when(mockrestTemplate).getForEntity(Matchers.anyString(), ArgumentMatchers.any(Class.class));
List<SampleObject1> list = sampleService.getGitHubUSersList();
assertNotNull(list);
错误
org.mockito.exceptions.misusing.NullInsteadOfMockException:
Argument passed to when() is null!
Example of correct stubbing:
doThrow(new RuntimeException()).when(mock).someMethod();
Also, if you use @Mock annotation don't miss initMocks()
at com.example.microservice.service.SampleServiceTest1.getGitHubUSersListTest(SampleServiceTest1.java:50)
【问题讨论】:
测试用例示例:github.com/naveenkulkarni029/products-api 首选RestOperations
,它是接口而不是实现类,在某些情况下可能更容易模拟。
【参考方案1】:
您的模拟设置错误getForEntity
不会返回List<SampleObject1>
,因此您不能将其设置为返回您需要返回ResponseEntity<SampleObject1[]>
。
所以来解决你的问题。声明一个新的 mock
@Mock
private ResponseEntity<SampleObject1[]> mockResponseEntity
doReturn(mockResponseEntity).when(mockrestTemplate).getForEntity(anyString(), any(Class.class));
doReturn(new SampleObject1[]sampoleObject1, sampoleObject2).when(mockResponseEntity).getBody();
【讨论】:
我怎样才能给你发私信?【参考方案2】:这应该可行。
我假设 restTemplate 响应是一个列表而不是一个数组。
@RunWith(MockitoJUnitRunner.class)
public class SampleServiceTest
@InjectMocks
private SampleService sampleService;
@Mock
private RestTemplate restTemplate;
@Test
public void name()
List<Pair> restResponseList = Arrays.asList(Pair.with("K1","V1"),Pair.with("K2","V2"));
when(restTemplate.getForEntity(any(String.class), Matchers.<Class<List>>any()))
.thenReturn(new ResponseEntity<>(
restResponseList,
new HttpHeaders(),
HttpStatus.OK));
List<Pair> testResponse =sampleService.getGitHubUSersList();
assertEquals(Pair.with("K1","V1"),testResponse.get(0));
assertEquals(Pair.with("K2","V2"),testResponse.get(1));
【讨论】:
我使用了一个 Pair 对象。您可以简单地将 Pair Class 替换为您的自定义类 SampleObject1【参考方案3】:我发现上面的代码存在两个潜在问题,我认为需要修复这些问题才能使您的测试正常运行:
-
您需要将
@RunWith(MockitoJUnitRunner.class)
应用到您的类声明行(即public class SampleServiceTest1
)。
使用@InjectMocks
和@Spy
注解时,需要有一个实际的实例。因此,我会将您的行 SampleService1 sampleService;
更改为 SampleService1 sampleService = new SampleService1();
有关执行这两项操作的示例,请查看this helpful Baeldung article on Mockito annotations。
【讨论】:
MocktioAnnotations.initMocks(this);
与@RunWith(MockitoJUnitRunner.class)
实现相同。在同一个领域使用@Spy
和@InjectMocks
会混淆概念,但它仍然可以工作。通过调用new SampleService1()
,您不会注入任何模拟。
@Tobb,这是一个 hack,但它可以工作,并且你的模拟将被注入。以上是关于如何在 Java Spring boot 中模拟 RestTemplate?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Spring Boot 中模拟数据库连接以进行测试?
如何使用 JUnit 在 Spring Boot 中的公共方法中模拟私有方法
如何在 Spring-boot 中不模拟服务类的情况下为 REST 控制器端点编写单元测试