web-dev-qa-db-ja.com

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を正しくモックするようにテストを修正するにはどうすればよいですか?

20
Akka Jaworek

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));
    }
22
Mindaugas
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);
15

これは非推奨の ArgumentMatchers クラスの例です

when(restTemplate.exchange(
                ArgumentMatchers.anyString(),
                ArgumentMatchers.any(HttpMethod.class),
                ArgumentMatchers.any(),
                ArgumentMatchers.<Class<String>>any()))
             .thenReturn(responseEntity);
12
itstata

私にとっては、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);
5
Abbin Varghese

私の側でこの作品。

ResourceBean resourceBean = initResourceBean();
ResponseEntity<ResourceBean> responseEntity  
    = new ResponseEntity<ResourceBean>(resourceBean, HttpStatus.ACCEPTED);
when(restTemplate.exchange(
    Matchers.anyObject(), 
    Matchers.any(HttpMethod.class),
    Matchers.<HttpEntity> any(), 
    Matchers.<Class<ResourceBean>> any())
 ).thenReturn(responseEntity);
3
chendu

RestTemplateインスタンスは、実際のオブジェクトでなければなりません。 RestTemplateの実際のインスタンスを作成し、@Spyにすると機能するはずです。

@Spy
private RestTemplate restTemplate = new RestTemplate();
0
Manoj Shrestha

残りの呼び出しを気にせずにサービスをテストすることを意図している場合は、テストを簡素化するためにユニットテストで注釈を使用しないことをお勧めします。

したがって、私の提案は、サービスをリファクタリングして、インジェクションコンストラクターを使用して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コンストラクターによって残りのテンプレートをモックするための直接アクセスができます。

0
Dherik

RestTemplateBuilderを使用している場合、通常はうまくいかないかもしれません。これをテストクラスにwhen(condition)と共に追加する必要があります。

@Before    
public void setup() {        
     ReflectionTestUtils.setField(service, "restTemplate", restTemplate);    
}
0
Debiprasad

小さなライブラリ を実装しました。これは非常に便利です。コンテキストを受信できるClientHttpRequestFactoryを提供します。そうすることにより、クエリパラメータの値の確認、ヘッダーの設定、逆シリアル化の動作確認など、すべてのクライアントレイヤーを通過できます。

0
Kier GRAY