【问题标题】:How do I mock Rest Template's getForEntity() method如何模拟 Rest Template 的 getForEntity() 方法
【发布时间】:2019-07-04 18:51:36
【问题描述】:

我是 mockito 新手,需要一些帮助,可能是一些关于如何模拟 Rest Template 的 getForEntity 和 postForEntity 方法的示例。下面是我想通过模拟 getForEntity 方法来编写 Junit 测试用例的代码。

SomeService.java

class SomeService
{
   //some private, static,  final data members
   public Map getService(String sNo, String uId, String en)
   {
      ResponseEntity <Map> response = new 
      RestTemplate().getForEntity("https://someurl.com/someService", 
      Map.class);
      Map body = response.getBody();
      //do something

      HttpEntity<?> request = new HttpEntity <>(payLoad, headers);
      //payload is Hash Map and headers is a LinkedMultiValueMap
      ResponseEntity <Map> response = new RestTemplate().postForEntity(url, 
      request, headers);
      return response.getBody(); 

   }   
}

我尝试过使用@Mock 和@InjectMocks 做一些事情。

TestSomeService.java

@RunWith(MockitoJunitRunner.class)
class TestSomeService
{
   @Mock
   RestTemplate restTemplate;
   @InjectMocks
   SomeService ser;
   /*Some data members*/
   @Before
   {
      HttpEntity <?> request = new HttpEntity<>(reqPayload, headers);
      Mockito.when(restTemplate.getForEntity("theUrl", 
      Map.class)).thenReturn(new ResponseEntity <Map>(someMap, 
      HttpStatus.OK));
      Mockito.when(restTemplate.postForEntity("anotherUrl", request, 
      Map.class)).thenReturn(new ResponseEntity <Map>(expectedMap, 
      HttpStatus.OK));

   }  
   @Test
   public void testGetService()
   {
       Map <String, Object> result = ser.getService("123", "abc", "QA");
   }    
}

【问题讨论】:

  • 那有什么问题呢?什么不工作?另外,你给MockitoAnnotations.initMocks(this)打过电话吗?
  • 问题是它没有被嘲笑。我没有得到我期待的答案。它每次都给出不同的输出。
  • 如果你能给出一些关于如何模拟它的示例代码,那将会很有帮助。

标签: java mockito junit4 resttemplate


【解决方案1】:

当你调用特定值时,你必须用ArgumentMatchers.eq() 包裹它。但是,您也可以使用anyString()any(Class class) 等。它们都是不言自明的。 Mockito tutorial.

@Before
public void init (){
    MockitoAnnotations.initMocks(this);

    HttpEntity <?> request = new HttpEntity<>(reqPayload, headers);

    Mockito.when(restTemplate.getForEntity(ArgumentMatchers.eq("theUrl"),ArgumentMatchers.any(Map.class)))
            .thenReturn(new ResponseEntity <Map>(someMap, HttpStatus.OK));
}

关于你的结构。这样你可以通过构造函数注入RestTemplate

public class ServiceTester {

    @Mock
    private RestTemplate restTemplate;

    private Service service;

    @Before
    public void init (){
        MockitoAnnotations.initMocks(this);

        service = new Service(restTemplate);

        HttpEntity <?> request = new HttpEntity<>(reqPayload, headers);

        Mockito.when(restTemplate.getForEntity(ArgumentMatchers.eq("theUrl"),ArgumentMatchers.any(Map.class)))
                .thenReturn(new ResponseEntity <Map>(someMap, HttpStatus.OK));
    }


}

class Service {

    private RestTemplate template;

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

    public Map doSomething () {
        // do something with template
    }
}

【讨论】:

  • 但在代码中,restTemplate 不是 SomeService 类中的类成员。如果我们使用@Mocks 和 InjectMocks 会起作用吗?
  • 嗯,这不是一个好的设计。首先,您应该将它移动到服务类的构造函数中,以便在您的应用程序中 Spring 可以注入它。这样您就可以为每个请求创建 2 个 RestTemplates。之后,您可以将您的模拟 RestTemplate bean 注入您在 Test 类中实例化的服务类。
  • 嗨@MensurQulami 对此stackoverflow.com/questions/59780621/… 有什么建议吗?
【解决方案2】:

我像这样模拟一个休息模板

@RunWith(SpringRunner.class)
public class Clazz {

    @Mock
    private RestTemplate restTemplate;
}

所以尝试使用 SpringRunner 而不是 MockitoRunner 也许它会工作

【讨论】:

  • 但在代码中,restTemplate 不是 SomeService 类中的类成员。getForEntity 是使用 new RestTemplate() 调用的,它不是类的成员。如果我们使用@Mocks 和 InjectMocks 会起作用吗?
  • 您是否尝试将 RestTemplate 调用移动到另一个方法并监视此方法?
【解决方案3】:

你必须注入RestTemplate你的服务SomeService。目前,您正在服务中创建一个新实例。这意味着,您不会获得 RestTemplate 的模拟实例,但您会获得真实类 RestTemplate 的全新实例。

你必须这样做:

class SomeService
{
   @Inject
   private RestTemplate restTemplate;   

   //some private, static,  final data members
   public Map getService(String sNo, String uId, String en)
   {
      ResponseEntity <Map> response = restTEmplate.getForEntity("https://someurl.com/someService", 
      Map.class);
      ...
   }
}

【讨论】:

    【解决方案4】:

    您确定要特别模拟一个 restTemplate 吗?

    不模拟 restTemplate 而是模拟一个答案怎么样?

    它还可以帮助您测试 restTemplate 行为。如果 restTemplate 得到 404 或 500 怎么办?

    这就是为什么我建议你使用MockRestServiceServer

    它有助于检查所有真实场景。

    【讨论】:

      【解决方案5】:

      如果您有权对 SomeService 类进行更改,我建议您执行以下操作。

      class SomeService
      {
         //some private, static,  final data members
         public Map getService(String sNo, String uId, String en)
         {
            ResponseEntity <Map> response = getForEntity("https://someurl.com/someService", Map.class);
            Map body = response.getBody();
            //do something
      
            HttpEntity<?> request = new HttpEntity <>(payLoad, headers);
            //payload is Hash Map and headers is a LinkedMultiValueMap
            ResponseEntity <Map> response = postForEntity(url, request, headers);
            return response.getBody(); 
         }   
      }
      

      正如您可能已经猜到的那样,getForEntitypostForEntity 方法已被提取出来,并且 RestTemplate 在其中被实例化——秘密地完成了它的工作。而且由于您想从一开始就模拟 RestTemplate,所以我们摆脱了它是一件好事——现在我们可以在没有任何要模拟的对象的情况下监视我们的服务。

          @RunWith(MockitoJunitRunner.class)
          class TestSomeService
          {
             @InjectMocks
             @Spy
             SomeService ser;
             /*Some data members*/
      
             @Before
             {
                HttpEntity <?> request = new HttpEntity<>(reqPayload, headers);
      
                doReturn(new ResponseEntity <Map>(someMap, HttpStatus.OK))
                  .when(ser).getForEntity("theUrl", Map.class));
      
                doReturn(new ResponseEntity <Map>(expectedMap, HttpStatus.OK))
                  .when(ser).postForEntity("anotherUrl", request, Map.class));
             }
      
             @Test
             public void testGetService()
             {
                 Map <String, Object> result = ser.getService("123", "abc", "QA");
             }    
          }
      

      【讨论】:

        猜你喜欢
        • 2021-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-28
        相关资源
        最近更新 更多