存根返回存根时初始化时存根失败

问题描述 投票:0回答:1

我有以下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 inded。

B)将RestTemplateBuilder插入setup()或测试中可以正常工作。也可以在其中或在按规范进行初始化时,将RestTemplate存入其中,也可以使用。但是,当我还在规范中的初始化时也对RestTemplateBuilder进行存根时:

package de.scrum_master.stackoverflow.q59630155

class MySpec extends Specification {
  // ...

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

  // ...
}

我得到一个

java.lang.NullPointerException: null

我这样做时也会遇到同样的异常

build() >> null

我怀疑在Spec的初始化时对restTemplate和restTemplateBuilder进行存根会导致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

编辑:一位同事建议这样做实际上是有意的,因为它可以防止堆栈中不确定的递归内存分配。

是错误,还是有其他原因导致它不起作用?

java spring maven resttemplate spock
1个回答
1
投票

再次查看您自己的代码:

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

您正在尝试在创建restTemplateBuilder存根对象之前对返回restTemplateBuilder的方法进行存根,这是一个自引用,类似于编写String text = "xy" + text。这也解释了为什么它分两步工作:首先创建存根实例,然后对引用先前创建的对象的方法进行存根。

没有错误。问题出在键盘前面。没有冒犯的意思,这在我之前也发生过。 ;-)

© www.soinside.com 2019 - 2024. All rights reserved.