2016-09-14 135 views
7

我有我需要通过REST问外部服务器的一些信息的服务:如何模拟REST模板交换?

public class SomeService { 

    public List<ObjectA> getListofObjectsA() { 
     List<ObjectA> objectAList = new ArrayList<ObjectA>(); 
     ParameterizedTypeReference<List<ObjectA>> typeRef = new ParameterizedTypeReference<List<ObjectA>>() {}; 
     ResponseEntity<List<ObjectA>> responseEntity = restTemplate.exchange("/objects/get-objectA", HttpMethod.POST, new HttpEntity<>(ObjectAList), typeRef); 
     return responseEntity.getBody(); 
    } 
} 

我怎么能写getListofObjectsA() JUnit测试?

我曾试图与下面:

@RunWith(MockitoJUnitRunner.class) 
public class SomeServiceTest { 
    private MockRestServiceServer mockServer; 

    @Mock 
    private RestTemplate restTemplate; 

    @Inject 
    private SomeService underTest; 

@Before 
public void setup() { 
    mockServer = MockRestServiceServer.createServer(restTemplate); 
    underTest = new SomeService(restTemplate); 
    mockServer.expect(requestTo("/objects/get-objectA")).andExpect(method(HttpMethod.POST)) 
      .andRespond(withSuccess("{json list response}", MediaType.APPLICATION_JSON)); 
} 

    @Test 
    public void testGetObjectAList() { 
    List<ObjectA> res = underTest.getListofObjectsA(); 
    Assert.assertEquals(myobjectA, res.get(0)); 
} 

但是上面的代码不工作,这表明responseEntittynull。我怎样才能纠正我的测试,以适当地模拟restTemplate.exchange

+1

任何人都有想法? –

回答

5

您不需要MockRestServiceServer对象。注释是@InjectMocks而不是@Inject。贝娄是一个示例代码,应该工作

@RunWith(MockitoJUnitRunner.class) 
public class SomeServiceTest { 
    @Mock 
    private RestTemplate restTemplate; 

    @InjectMocks 
    private SomeService underTest; 

    @Test 
    public void testGetObjectAList() { 
     ObjectA myobjectA = new ObjectA(); 
     //define the entity you want the exchange to return 
     ResponseEntity<List<ObjectA>> myEntity = new ResponseEntity<List<ObjectA>>(HttpStatus.ACCEPTED); 
     Mockito.when(restTemplate.exchange(
      Matchers.eq("/objects/get-objectA"), 
      Matchers.eq(HttpMethod.POST), 
      Matchers.<HttpEntity<List<ObjectA>>>any(), 
      Matchers.<ParameterizedTypeReference<List<ObjectA>>>any()) 
     ).thenReturn(myEntity); 

     List<ObjectA> res = underTest.getListofObjectsA(); 
     Assert.assertEquals(myobjectA, res.get(0)); 
    } 
4
ResponseEntity<String> responseEntity = new ResponseEntity<String>("sampleBodyString", HttpStatus.ACCEPTED); 
when(restTemplate.exchange(
          Matchers.anyString(), 
          Matchers.any(HttpMethod.class), 
          Matchers.<HttpEntity<?>> any(), 
          Matchers.<Class<String>> any() 
         ) 
         ).thenReturn(responseEntity); 
1

对于我来说,我不得不使用Matchers.any(URI.class),而不是

Mockito.when(restTemplate.exchange(Matchers.any(URI.class), Matchers.any(HttpMethod.class), Matchers.<HttpEntity<?>> any(), Matchers.<Class<Object>> any())).thenReturn(myEntity); 
0

我实现a small library这是非常有用的。它提供了一个可以接收一些上下文的ClientHttpRequestFactory。通过这样做,它允许遍历所有客户端层,例如检查查询参数是否有价值,设置了标头,并检查反序列化是否正常。

0

如果您的意图是测试服务而不关心其他呼叫,我会建议您不要在单元测试中使用任何注释来简化测试。

因此,我的建议是重构您的服务来使用注入构造函数来接收resttemplate。这将有助于测试。例如:

@Service 
class SomeService { 
    @AutoWired 
    SomeService(TestTemplateObjects restTemplateObjects) { 
     this.restTemplateObjects = restTemplateObjects; 
    } 
} 

的RestTemplate作为组分,被注入后嘲笑:

@Component 
public class RestTemplateObjects { 

    private final RestTemplate restTemplate; 

    public RestTemplateObjects() { 
     this.restTemplate = new RestTemplate(); 
     // you can add extra setup the restTemplate here, like errorHandler or converters 
    } 

    public RestTemplate getRestTemplate() { 
     return restTemplate; 
    } 
} 

而且测试:

public void test() { 

    when(mockedRestTemplateObject.get).thenReturn(mockRestTemplate); 

    //mock restTemplate.exchange 
    when(mockRestTemplate.exchange(...)).thenReturn(mockedResponseEntity); 

    SomeService someService = new SomeService(mockedRestTemplateObject); 
    someService.getListofObjectsA(); 
} 

通过这种方式,你可以直接访问嘲笑由SomeService构造函数创建其余模板。