我的控制器呼叫服務來發布有關汽車的資訊,如下所示,它作業正常。但是,我的單元測驗因IllegalArgumentException: URI is not absolute例外而失敗,SO 上的所有帖子都無法對此提供幫助。
這是我的控制器
@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;
}
}
這是我的服務類:
@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;
}
}
但是,我無法讓我的單元測驗作業。下面的測驗拋出IllegalArgumentException: URI is not absolute例外:
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);
}
}
更新 1
我想出了為什么會拋出“ Uri 不是絕對的” 執行。這是因為在我carService上面,我使用從檔案@Value注入,但在單元測驗中,沒有注入。uriapplication.properties
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.
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.
This contradicts with using mocking in unit tests.
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. 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.
uj5u.com熱心網友回復:
您需要正確構建被測系統。目前,MyServiceImpl.uri為空。
由于 Mockito 不支持部分注入,需要在測驗中手動構建實體。
我會:
使用建構式注入:
@Service
public class MyServiceImpl implements MyService {
private String uri;
public MyServiceImpl(@Value("${myUri}") uri) {
this.uri = uri;
}
手動構建實體:
- 洗掉@Mock 和@InjectMocks
- 洗掉 Mockito.initMocks 呼叫
- 在測驗中使用 Mockito.mock 和建構式
public class CarServiceTest {
public static String TEST_URI = "YOUR_URI";
RestTemplate restTemplateMock = Mockito.mock(RestTemplate.class);
CarServiceImpl carServiceSut = new CarServiceImpl(restTemplateMock, TEST_URI):
}
uj5u.com熱心網友回復:
嘗試將 URI 更改為
String uri = "http://some/fake/url";
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/359929.html
標籤:spring-boot unit-testing mockito resttemplate
