Как смоделировать RequestEntity.put () и restTemplate.exchange () в Spock groovy - PullRequest
0 голосов
/ 25 сентября 2019

Java-код для вызова API

Я хочу знать, как проверить две нижеследующие строки кода.

private void api(){
    //Code to call an API and i want to test this in groovy spock
    HttpHeaders httpHeaders = new HttpHeaders();      
    httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON); 
    httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    RestTemplate restTemplate = new RestTemplate();
    String url ="url";
    String body ="body";
    //How to mock below line
    RequestEntity<String> requestEntity = RequestEntity.put(new URI(url)).contentType(MediaType.APPLICATION_JSON).body(body);
    //And this line
    ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity,String.class);
    HttpStatus StatusCode = responseEntity.getStatusCode();
}

1 Ответ

1 голос
/ 26 сентября 2019

Это не вопрос Спока как таковой (вы не представили ни одной строки спецификации Спока, поэтому никто не знает, что вы пробовали до сих пор), а скорее вопрос разработки программного обеспечения или общего тестирования.Проблема с тестированием спагетти-кода - и здесь я имею в виду код, который одновременно что-то делает и создает множество объектов - заключается в том, что снаружи нет доступа к объектам, созданным внутри метода и хранящимся в локальной переменной.Есть два способа реорганизовать ваш код для лучшей тестируемости:

  • Если это имеет смысл, измените код так, чтобы позволить пользователю вводить зависимости извне вместо создания кодаих внутренне.Пожалуйста, введите "внедрение зависимостей" в Google и найдите варианты, такие как

    • инъекция в конструктор,
    • инъекция сеттера,
    • инъекция параметра метода,
    • инъекция поля, когдаиспользование инструментов / парадигм, таких как CDI.
  • Другой способ состоит в том, чтобы разделить части метода, создающие объекты, на методы меньшего производителя (или создателя, или фабрики), которые затем вы можетеперезаписать (заглушку) в соответствии с вашим выбором в тесте при использовании объекта частичного макета (шпиона).Спок предоставляет таких шпионов, чтобы вы могли легко их использовать.

Я собираюсь показать последний подход для вашей информации:

package de.scrum_master.stackoverflow.q58101434;

import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;

public class MyRestApi {
  public HttpStatus api() throws URISyntaxException {
    //Code to call an API and i want to test this in groovy spock
    HttpHeaders httpHeaders = createHttpHeaders();
    RestTemplate restTemplate = createRestTemplate();
    String url ="url";
    String body ="body";
    //How to mock below line
    RequestEntity<String> requestEntity = createRequestEntity(url, body);
    //And this line
    ResponseEntity<String> responseEntity = executeRequest(restTemplate, requestEntity);
    return responseEntity.getStatusCode();
  }

  HttpHeaders createHttpHeaders() {
    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
    httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    return httpHeaders;
  }

  RestTemplate createRestTemplate() {
    return new RestTemplate();
  }

  RequestEntity<String> createRequestEntity(String url, String body) throws URISyntaxException {
    return RequestEntity.put(new URI(url)).contentType(MediaType.APPLICATION_JSON).body(body);
  }

  ResponseEntity<String> executeRequest(RestTemplate restTemplate, RequestEntity<String> requestEntity) {
    return restTemplate.exchange(requestEntity,String.class);
  }
}

Посмотрите, как методболее структурированным и более читаемым сейчас (все еще можно улучшить, я просто сделал это быстро и грязно)?Обратите особое внимание на вспомогательные методы createRequestEntity и executeRequest.

Теперь вот как вы можете написать свой тест Спока:

package de.scrum_master.stackoverflow.q58101434

import org.springframework.http.HttpStatus
import org.springframework.http.RequestEntity
import org.springframework.http.ResponseEntity
import spock.lang.Specification
import spock.lang.Unroll

class MyRestApiTest extends Specification {
  @Unroll
  def "API returns status code #statusCode"() {
    given: "prepare mocks + spy"
    RequestEntity<String> requestEntity = Mock()
    ResponseEntity<String> responseEntity = Mock() {
      getStatusCode() >> httpStatus
    }
    MyRestApi myRestApi = Spy() {
      createRequestEntity(_, _) >> requestEntity
      executeRequest(_, _) >> responseEntity
    }

    when: "execute API method"
    def result = myRestApi.api()

    then: "check expected results"
    // This actually only tests mockfunctionality, your real test would look differently
    statusCode == result.value()
    reasonPhrase == result.reasonPhrase

    where:
    httpStatus                   | statusCode | reasonPhrase
    HttpStatus.OK                | 200        | "OK"
    HttpStatus.MOVED_PERMANENTLY | 301        | "Moved Permanently"
    HttpStatus.UNAUTHORIZED      | 401        | "Unauthorized"
  }
}

Не стесняйтесь задавать (связанные!)вопросы, если вы не понимаете этот код.Я советую вам узнать больше о чистом коде, тестируемости, пробном тестировании в целом, а также о Споке в частности.

...