简体   繁体   English

Spring Mockito 测试 RestTemplate.postForEntity 抛出 IllegalArgumentException:URI 不是绝对的

[英]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中,我使用@Valueapplication.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 不支持部分注入。

  • drop @Mock and @InjectMocks删除 @Mock 和 @InjectMocks
  • drop Mockito.initMocks call放弃 Mockito.initMocks 调用
  • use Mockito.mock and constructor in test在测试中使用 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):

}

try to change the URI as尝试将 URI 更改为

String uri = "http://some/fake/url";

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Spring Boot RestTemplate 抛出 java.lang.IllegalArgumentException: [http://test.com?value=Dummy text #test] 不是有效的 URI - Spring Boot RestTemplate throws java.lang.IllegalArgumentException: [http://test.com?value=Dummy text #test] is not a valid URI 为什么我在 restTemplate.postforEntity 之后的值为 null - Why is my value after restTemplate.postforEntity is null Mockito 在 RestTemplate.exchange Springboot 中返回“java.lang.IllegalArgumentException: URI 不是绝对的” - Mockito is returning "java.lang.IllegalArgumentException: URI is not absolute" in RestTemplate.exchange Springboot org.springframework.web.client.HttpClientErrorException 400 RestTemplate.postForEntity - org.springframework.web.client.HttpClientErrorException 400 RestTemplate.postForEntity 当实体具有与预期不同的字段名称时如何调用restTemplate.postForEntity - how to call restTemplate.postForEntity when entity is having different field name than expected 通过服务调用时文件上传失败,即restTemplate.postForEntity - File-upload fails when called via a service i.e restTemplate.postForEntity Spring Boot RestTemplate postForEntity 但主体为空 - Spring Boot RestTemplate postForEntity but with null body FOP 在 jar 中运行时抛出“IllegalArgumentException: URI is not absolute” - FOP throws “IllegalArgumentException: URI is not absolute” when running in a jar 在使用@WebFluxTests 测试的 controller 中使用 WebClient 会抛出 java.lang.IllegalArgumentException: URI is not absolute - Using WebClient in a controller tested with @WebFluxTests throws java.lang.IllegalArgumentException: URI is not absolute RestTemplate postForEntity 返回 DTO 列表 - RestTemplate postForEntity return List of DTO
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM