【问题标题】:How to mock RestTemplate in Java Spring?如何在 Java Spring 中模拟 RestTemplate?
【发布时间】:2017-07-13 09:29:55
【问题描述】:
public class ServiceTest {
    @Mock
    RestTemplate restTemplate = new RestTemplate();
    @InjectMocks
    Service service = new Service();
    ResponseEntity responseEntity = mock(ResponseEntity.class);

    @Test
    public void test() throws Exception {
        Mockito.when(restTemplate.getForEntity(
                Mockito.anyString(),
                Matchers.any(Class.class)
                ))
                .thenReturn(responseEntity);
        boolean res = service.isEnabled("something");
        Assert.assertEquals(res, false);
    }

我尝试测试一个简单的服务测试,包括一个 restclient。看来我还没有成功模拟RestTemplate。看起来代码获取的是真实数据而不是模拟数据。任何人都可以帮助我。

服务本身将如下所示:

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

【问题讨论】:

    标签: java unit-testing spring-mvc mockito


    【解决方案1】:

    问题在于,在您的isEnabled 中,您正在创建一个新的 RestTemplate。这是错误的,原因有两个,一是您无法模拟它,因为您正在创建一个新对象,二是最好避免为每个请求创建新对象。 RestTemplate 是线程安全的,因此可以作为服务类成员,在多个线程中使用。

    将您的服务类更改为以下内容:

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

    现在您的 RestTemplate 已成为类成员,您现在可以通过以下两种方式之一正确地模拟。一,使用@InjectMock 注入它,或者使用您从测试中调用的setter 方法。

    由于您在代码中使用 InjectMock,我们可以使用它。

    @RunWith(MockitoJUnitRunner.class) 
    public class ServiceTest {
        @Mock
        RestTemplate restTemplate;
        @InjectMocks
        @Spy
        Service service;
        ResponseEntity responseEntity = mock(ResponseEntity.class);
    
        @Test
        public void test() throws Exception {
            Mockito.when(restTemplate.getForEntity(
                    Mockito.anyString(),
                    ArgumentMatchers.any(Class.class)
                    ))
                    .thenReturn(responseEntity);
            boolean res = service.isEnabled("something");
            Assert.assertEquals(res, false);
        }
    

    请注意,我做了一些更改。首先,我删除了new RestTemplate()new Service()。您应该让 mockito 为您创建这些。通过使用 @Mock@Spy 注释它们,您将确保 Mockito 会为您创建它们,更重要的是,会将模拟注入到您的 service 对象中。

    【讨论】:

      【解决方案2】:

      Spring MVC 的测试框架提供了 MockRestServiceServer 类,用于对 RESTful 服务代码进行单元测试。

      这是tutorial 的使用说明。

      【讨论】:

      【解决方案3】:

      如果你使用@Autowired,你可以使用 MockRestServiceServer。 以下是示例。

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

      @Service 需要使用@Autowired 自动创建对象。

      【讨论】:

      • 我试过了,但是会返回restTemplate为null的错误。看起来我无法注入 restTemplate bean。我还能做些什么来测试它吗?我只需要模拟 RestTemplete 的响应。
      • 抱歉,我错过了在课堂上添加重要性注释。请再看我的回答。
      猜你喜欢
      • 2020-05-01
      • 1970-01-01
      • 2019-06-06
      • 1970-01-01
      • 1970-01-01
      • 2019-12-21
      • 2018-08-14
      • 2019-07-01
      • 1970-01-01
      相关资源
      最近更新 更多