[英]Spring Mockito test of RestTemplate.postForEntity throws IllegalArgumentException: URI is not absolute
My Controller calls the service to post information about a car like below and it works fine.我的 Controller 调用该服务来发布有关汽车的信息,如下所示,它工作正常。 However, my unit test fails with the IllegalArgumentException: URI is not absolute exception and none of the posts on SO were able to help with it.
但是,我的单元测试失败并出现IllegalArgumentException: URI is not absolute exception 并且 SO 上的所有帖子都无法提供帮助。
Here is my controller这是我的 controller
@RestController
@RequestMapping("/cars")
public class CarController {
@Autowired
CarService carService;
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<CarResponse> getCar(@RequestBody CarRequest carRequest, @RequestHeader HttpHeaders httpHeaders) {
ResponseEntity<CarResponse> carResponse = carService.getCard(carRequest, httpHeaders);
return carResponse;
}
}
Here is my service class:这是我的服务 class:
@Service
public class MyServiceImpl implements MyService {
@Value("${myUri}")
private String uri;
public void setUri(String uri) { this.uri = uri; }
@Override
public ResponseEntity<CarResponse> postCar(CarRequest carRequest, HttpHeaders httpHeaders) {
List<String> authHeader = httpHeaders.get("authorization");
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", authHeader.get(0));
HttpEntity<CarRequest> request = new HttpEntity<CarRequest>(carRequest, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<CarResponse> carResponse = restTemplate.postForEntity(uri, request, CarResponse.class);
return cardResponse;
}
}
However, I am having trouble getting my unit test to work.但是,我无法让我的单元测试正常工作。 The below tests throws IllegalArgumentException: URI is not absolute exception:
以下测试抛出IllegalArgumentException: URI is not absolute exception:
public class CarServiceTest {
@InjectMocks
CarServiceImpl carServiceSut;
@Mock
RestTemplate restTemplateMock;
CardResponse cardResponseFake = new CardResponse();
@BeforeEach
void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
cardResponseFake.setCarVin(12345);
}
@Test
final void test_GetCars() {
// Arrange
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", anyString());
ResponseEntity<CarResponse> carResponseEntity = new ResponseEntity(carResponseFake, HttpStatus.OK);
String uri = "http://FAKE/URI/myapi/cars";
carServiceSut.setUri(uri);
when(restTemplateMock.postForEntity(
eq(uri),
Mockito.<HttpEntity<CarRequest>> any(),
Mockito.<Class<CarResponse>> any()))
.thenReturn(carResponseEntity);
// Act
**// NOTE: Calling this requires real uri, real authentication,
// real database which is contradicting with mocking and makes
// this an integration test rather than unit test.**
ResponseEntity<CarResponse> carResponseMock = carServiceSut.getCar(carRequestFake, headers);
// Assert
assertEquals(carResponseEntity.getBody().getCarVin(), 12345);
}
}
UPDATE 1更新 1
I figured out why the " Uri is not absolute " exection is thrown.我弄清楚为什么会抛出“ Uri is not absolute ”执行。 It is because in my
carService
above, I use @Value
to inject uri
from application.properties
file, but in unit tests, that is not injected.这是因为在我上面的
carService
中,我使用@Value
从application.properties
文件中注入uri
,但在单元测试中,没有注入。
So, I added public property to be able to set it and updated the code above, but then I found that the uri
has to be a real uri to a real backend, requiring a real database.所以,我添加了公共属性以便能够设置它并更新上面的代码,但后来我发现
uri
必须是真实后端的真实uri,需要真实的数据库。
In other words, if the uri
I pass is a fake uri, the call to carServiceSut.getCar
above, will fail which means this turns the test into an integration test.换句话说,如果我传递的
uri
是假 uri,那么上面对carServiceSut.getCar
的调用将失败,这意味着这会将测试变成集成测试。
This contradicts with using mocking in unit tests.这与在单元测试中使用 mocking 相矛盾。 I dont want to call real backend, the
restTemplateMock
should be mocked and injected into carServiceSut
since they are annotated as @Mock
and @InjectMock
respectively.我不想调用真正的后端,
restTemplateMock
应该被模拟并注入到carServiceSut
中,因为它们分别被注释为@Mock
和@InjectMock
。 Therefore, it whould stay a unit test and be isolated without need to call real backend.因此,它应该是一个单元测试并被隔离,而不需要调用真正的后端。 I have a feeling that Mockito and RestTemplate dont work well together.
我感觉 Mockito 和 RestTemplate 不能很好地协同工作。
I would:我会:
Use constructor injection:使用构造函数注入:
@Service
public class MyServiceImpl implements MyService {
private String uri;
public MyServiceImpl(@Value("${myUri}") uri) {
this.uri = uri;
}
Construct the instance manually in test.在测试中手动构建实例。 Mockito has no support for partial injection.
Mockito 不支持部分注入。
public class CarServiceTest {
public static String TEST_URI = "YOUR_URI";
RestTemplate restTemplateMock = Mockito.mock(RestTemplate.class);
CarServiceImpl carServiceSut = new CarServiceImpl(restTemplateMock, TEST_URI):
}
try to change the URI as尝试将 URI 更改为
String uri = "http://some/fake/url";
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.