简体   繁体   English

如何使用 MockRestServiceServer 模拟 RestTemplate?

[英]How to mock RestTemplate with MockRestServiceServer?

@RunWith(MockitoJUnitRunner.class)
public class FeatureFlipperManagerTest {
    @Autowired
    RestTemplate restTemplate = new RestTemplate();
    @Autowired
    Service service = new Service();
    MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);

    @Test
    public void test() throws Exception {
      mockServer.expect(requestTo(Mockito.anyString()))
                .andRespond(withSuccess("{\"enabled\":true}", MediaType.APPLICATION_JSON));
        boolean res = service.isEnabled("xxx");
        mockServer.verify();
        Assert.assertEquals(true, res);
    }
}

I have MockRestServiceServer to mock restTemplete in a service.我有 MockRestServiceServer 来模拟服务中的 restTemplete。 But it always fail.但它总是失败。 it shows the error as java.lang.AssertionError: Further request(s) expected 0 out of 1 were executed .它将错误显示为java.lang.AssertionError: Further request(s) expected 0 out of 1 were executed Any one could let me know where I did not do it right.任何人都可以让我知道我哪里做得不对。

The service itself will looks as this:服务本身将如下所示:

public class Service{
    public boolean isEnabled(String xxx) {
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = restTemplate.getForEntity("someurl",String.class);
        if(...)return true;
        return false;
    }
}

First of all, your Service class creates a new instance of RestTemplate on every request.首先,您的Service类为每个请求创建一个 RestTemplate 的新实例。 I cannot stress enough how bad practice it is.我怎么强调这是多么糟糕的做法。 Create a bean of type RestTemplate and inject it into your Service bean (it is most likely already created - depending on the Spring MVC version you are using).创建一个 RestTemplate 类型的 bean 并将其注入您的Service bean(它很可能已经创建 - 取决于您使用的 Spring MVC 版本)。

Once you have it, then both RestTemplates: one in your Service bean and one injected into FeatureFlipperManagerTest will be the same and testing with MockRestServiceServer will be possible.一旦你有了它,那么两个 RestTemplates:一个在你的Service bean 中和一个注入到FeatureFlipperManagerTest将是相同的,并且可以使用MockRestServiceServer进行测试。

EDIT - to be more explicit:编辑 - 更明确:

Modify your Service class to:将您的Service类修改为:

@Component
public class Service {

    private RestTemplate restTemplate;  

    @Autowired 
    public Service(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public boolean isEnabled(String xxx) {
        ResponseEntity<String> response = restTemplate.getForEntity("someurl",String.class);
        if(...)return true;
        return false;
    }
}

and your test class to:和您的测试类:

@RunWith(MockitoJUnitRunner.class)
public class FeatureFlipperManagerTest {
    @Autowired
    RestTemplate restTemplate;

    @Autowired
    Service service;

    MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);

    @Test
    public void test() throws Exception {
      mockServer.expect(requestTo(Mockito.anyString()))
                .andRespond(withSuccess("{\"enabled\":true}", MediaType.APPLICATION_JSON));
        boolean res = service.isEnabled("xxx");
        mockServer.verify();
        Assert.assertEquals(true, res);
    }
}

If this fails with exception saying that there is no RestTemplate bean present then please paste info about version of Spring (Spring Boot?) you are using.如果此操作失败并显示不存在RestTemplate bean 的异常,请粘贴有关您正在使用的 Spring(Spring Boot?)版本的信息。

I think you mean you want to use RestTemplate which is provided by spring, so you should createServer after the spring autowired the RestTemplate.我想你的意思是你想使用 spring 提供的 RestTemplate,所以你应该在 spring 自动装配 RestTemplate 之后 createServer。 I think you can do it like this:我认为你可以这样做:

@RunWith(MockitoJUnitRunner.class)
public class FeatureFlipperManagerTest {
    @Autowired
    RestTemplate restTemplate;

    Service service;
    MockRestServiceServer mockServer;

    @Before
    public void init() {
        service = new Service(); 
        service.setRestTemplate(restTemplate);
        // If you have autowired restTemplate in Service, you can just autowired the service
        mockServer = MockRestServiceServer.createServer(restTemplate);
    }

    @Test
    public void test() throws Exception {
      mockServer.expect(requestTo(Mockito.anyString()))
                .andRespond(withSuccess("{\"enabled\":true}", MediaType.APPLICATION_JSON));
        boolean res = service.isEnabled("xxx");
        mockServer.verify();
        Assert.assertEquals(true, res);
    }
}

This is not an answer to your question, but just in case anyone comes across this question in 2021… With Spring Boot Testing, you may want to take advantage of testing the REST slice only with @RestClientTest .这不是您问题的答案,但以防万一有人在 2021 年遇到这个问题……使用 Spring Boot 测试,您可能希望仅使用@RestClientTest来测试 REST 切片。 This creates a RestTemplateBuilder bean only by default, if you want an auto-wired RestTemplate just add one bit of configuration as below.这只会在默认情况下创建一个RestTemplateBuilder bean,如果你想要一个自动连接的RestTemplate只需添加一点配置,如下所示。 (The example is in Kotlin, using Java instead remains as an excercise to the reader.) (这个例子在 Kotlin 中,使用 Java 仍然是读者的练习。)

@AutoConfigureWebClient(registerRestTemplate = true)
@RestClientTest(Service::class)
class AdkClientTest @Autowired constructor(
    private val mockRestServiceServer: MockRestServiceServer,
    private val service: Service
) {
    // …
}

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM