【问题标题】:How to mock RestTemplate with MockRestServiceServer?如何使用 MockRestServiceServer 模拟 RestTemplate?
【发布时间】:2017-02-23 07:42:44
【问题描述】:
@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);
    }
}

我有 MockRestServiceServer 在服务中模拟 restTemplete。但它总是失败。它显示错误为java.lang.AssertionError: Further request(s) expected 0 out of 1 were executed。任何人都可以让我知道我哪里做得不对。

服务本身将如下所示:

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;
    }
}

【问题讨论】:

  • 问题是您正在模拟的RestTemplate 没有作为依赖项传递给Service。您在 isEnabled 方法中创建了一个 new RestTemplate(),它不能被这样模拟。
  • 另外,您可能打算使用anyThing() 而不是requestTo(Mockito.anyString()),这只会期望一个空字符串作为URL,失败。

标签: java spring mockito resttemplate mockrestserviceserver


【解决方案1】:

首先,您的Service 类会在每个请求上创建一个新的 RestTemplate 实例。我不能强调这是多么糟糕的做法。创建一个 RestTemplate 类型的 bean 并将其注入您的 Service bean(它很可能已经创建 - 取决于您使用的 Spring MVC 版本)。

一旦你拥有它,那么两个 RestTemplates:一个在你的 Service bean 中,一个注入到 FeatureFlipperManagerTest 中将是相同的,并且可以使用 MockRestServiceServer 进行测试。

编辑 - 更明确地说:

将您的 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;
    }
}

和你的测试类:

@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);
    }
}

如果此操作失败并提示不存在RestTemplate bean,请粘贴有关您正在使用的 Spring(Spring Boot?)版本的信息。

【讨论】:

  • 我想您的评论是正确的,尽管我不确定如何解决我的问题。如果我不能创建 restTemplate bean。我还能做些什么来模拟一个 restTemplete 吗?实际上我只需要模拟 get 调用的响应。有没有办法做到这一点?
【解决方案2】:

我认为你的意思是你想使用 spring 提供的 RestTemplate,所以你应该在 spring 自动装配 RestTemplate 之后 createServer。我认为你可以这样做:

@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);
    }
}

【讨论】:

  • 我找不到名为 setRestTemplate(restTemplate) 的方法。为什么?
  • 因为 restTemplate 是使用 @Autowired 注释设置的。这是特定于 Spring 的。阅读“现场注入”和“构造函数注入”。
【解决方案3】:

这不是您问题的答案,但以防万一有人在 2021 年遇到此问题……使用 Spring Boot 测试,您可能希望仅使用 @RestClientTest 来测试 REST 切片。这仅默认创建一个RestTemplateBuilder bean,如果您想要一个自动连接的RestTemplate,只需添加如下配置。 (这个例子是在 Kotlin 中,使用 Java 仍然是读者的练习。)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-13
    • 1970-01-01
    • 1970-01-01
    • 2019-12-11
    • 1970-01-01
    • 2018-05-22
    • 2019-12-21
    • 1970-01-01
    相关资源
    最近更新 更多