Заглушка при инициализации завершается неудачно, когда заглушка возвращает заглушку - PullRequest
0 голосов
/ 07 января 2020

У меня есть следующий код Spring для тестирования с помощью Spock:

@Service
@RequiredArgsConstructor
public class MyService {
  private final RestTemplateBuilder restTemplateBuilder;
  // ...

  public Path downloadFile(String url) {
    try {
      ResponseEntity<byte[]> response = buildRestTemplate().getForEntity(url, byte[].class);
      File tempFileZip = File.createTempFile("myTempFile", ".zip");
      FileUtils.writeByteArrayToFile(tempFileZip, response.getBody());
      return tempFileZip.toPath();
    } catch (Exception e) {
      // ...
    }
  }

  private RestTemplate buildRestTemplate() {
    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    Proxy proxy = new Proxy(/*...*/);
    requestFactory.setProxy(proxy);
    return restTemplateBuilder.requestFactory(() -> requestFactory).build();
  }
}

В этом коде загружается файл. У меня есть пример файла в моей папке test / resources, который я хочу передать в результате тупой загрузки. Это один из способов заставить его работать, и у меня есть несколько вопросов по этому поводу:

package de.scrum_master.stackoverflow.q59630155

class MySpec extends Specification {

  RestTemplate restTemplate = Stub {
    getForEntity(_, byte[].class) >>
      ResponseEntity.ok(
        Files.readAllBytes(
          Paths.get(
            getClass()
              .getResource("/data/MySample/MySample.zip")
              .toURI()
          )
        )
      )
  }
  RestTemplateBuilder restTemplateBuilder = Stub()
  def myService = new MyService(restTemplateBuilder)

  def setup() {
    with(restTemplateBuilder) {
      requestFactory(_) >> restTemplateBuilder
      build() >> restTemplate
    }
  }

  def "downloadFile"() {
    when:
    def response = myService.downloadFile()

    then:
    // ...

    cleanup:
    Files.delete(response)
  }
}

A) Я хотел бы лучше понять, почему путь файла ресурсов оценивается через отладчик для ... target / test-classes / data / ebaRegistrySample / ebaRegistrySample.zip вместо чего-то, содержащего / test / resources Это из-за maven?

РЕДАКТИРОВАТЬ: В комментариях было дано ответ, что это из-за maven inded.

B) Заглушка RestTemplateBuilder в setup () или в тесте работает нормально. Также работает заглушка RestTemplate там или при инициализации в spe c, как показано, также работает. Но когда я также заглушаю RestTemplateBuilder при инициализации в spe c:

package de.scrum_master.stackoverflow.q59630155

class MySpec extends Specification {
  // ...

  RestTemplateBuilder restTemplateBuilder = Stub {
      requestFactory(_) >> restTemplateBuilder
      build() >> restTemplate
  }

  // ...
}

, я получаю

java.lang.NullPointerException: null

Я получаю то же исключение, когда я

build() >> null

Я подозреваю, что заглушка restTemplate и restTemplateBuilder при инициализации в Spe c приводит к тому, что restTamplate еще не имеет значения, когда restTemplateBuilder пытается получить к нему доступ. Кажется, что цепочка заглушек при инициализации должна работать, так что это может быть ошибкой.

Это ошибка или есть другая причина, почему она не работает?

РЕДАКТИРОВАТЬ: Это работает, когда я заглушаю метод requestFactory отдельно после инициализации. Так что это просто другая ошибка в случае C.

C) Заготовка RestTemplateBuilder при его инициализации не работает вообще. В то время как предыдущий случай приводит к исключению, размещение его в setup () или в тесте:

package de.scrum_master.stackoverflow.q59630155

class MySpec extends Specification {

  def "downloadFile"() {
    setup:
    RestTemplate restTemplate = Stub {
    getForEntity(_, byte[].class) >>
      ResponseEntity.ok(
        Files.readAllBytes(
          Paths.get(
            getClass()
              .getResource("/data/MySample/MySample.zip")
              .toURI()
          )
        )
      )
    }
    RestTemplateBuilder restTemplateBuilder = Stub() {
      requestFactory(_) >> restTemplateBuilder
      build() >> restTemplate
    }
    def myService = new MyService(restTemplateBuilder)

    // ...
  }
}

фактически приводит к ошибке компиляции:

requestFactory(_) >> restTemplateBuilder
No candidates found for method call restTemplateBuilder

РЕДАКТИРОВАТЬ: A Коллега предполагает, что это на самом деле предназначено, потому что оно защищает от неопределенного рекурсивного выделения памяти в стеке.

Это ошибка или есть другая причина, почему она не работает?

1 Ответ

1 голос
/ 28 января 2020

Снова посмотрите на свой собственный код:

RestTemplateBuilder restTemplateBuilder = Stub {
  requestFactory(_) >> restTemplateBuilder
  build() >> restTemplate
}

Вы пытаетесь заглушить метод, возвращающий restTemplateBuilder до того, как объект-заглушку restTemplateBuilder создан, это самоссылка, похожая на написание String text = "xy" + text. Это также объясняет, почему он работает в два этапа: сначала создайте экземпляр заглушки, а затем добавьте метод, ссылающийся на ранее созданный объект.

Ошибок нет. Проблема сидит перед клавиатурой. Без обид, это тоже случалось со мной раньше. ;-)

...