【问题标题】:Unable to generate the Spring rest docs using Cucumber无法使用 Cucumber 生成 Spring 休息文档
【发布时间】:2017-11-21 21:20:24
【问题描述】:

我正在尝试使用 spring cucumber jvm 测试我们服务的 rest API 的 spring rest 文档,但是当我尝试执行该场景时,最终会出现空指针异常,因为框架无法初始化 Junit 上下文。

错误信息:

java.lang.NullPointerException at 
org.springframework.restdocs.ManualRestDocumentation.beforeO‌​peration(ManualRestD‌​ocumentation.java:90‌​) at 
org.springframework.restdocs.JUnitRestDocumentation.beforeOp‌​eration(JUnitRestDoc‌​umentation.java:76)

代码:

private AppProperties props;
@Before("@rest") public void beforeScenario() { 
     JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation( "target/generated-snippets" );
     System.out.println( "jUnitRestDocumentation " +restDocumentation );
     spec = new RequestSpecBuilder().addFilter( documentationConfiguration( restDocumentation ) ).build();
     System.out.println( "\n spec init .. " +restDocumentation );
}

步骤定义代码:

@Given("^create a rest document for VHR API$")
public void create_a_rest_document_for_VHR_API() throws Throwable {
    estAssured.given( spec )
        .accept( "application/json" )
        .filter( document( "vhrdocument" ) ) .when() 
        .get( props.getVhrrequesturl() + "/vhrData/{vehicleID}", "5VW4T7AU0FM029999" ) .then().log().all();
}

【问题讨论】:

  • 错误消息:org.springframework.restdocs.JUnitRestDocumentation.beforeOperation(JUnitRestDocumentation.java:76) 中 org.springframework.restdocs.ManualRestDocumentation.beforeOperation(ManualRestDocumentation.java:90) 中的 java.lang.NullPointerException
  • @Autowired 私有 AppProperties 道具; @Before("@rest") public void beforeScenario() { JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("target/generated-sn-ps" ); System.out.println("jUnitRestDocumentation" +restDocumentation); spec = new RequestSpecBuilder().addFilter(documentationConfiguration(restDocumentation)).build(); System.out.println("\n 规范初始化 .." +restDocumentation ); }
  • 步骤定义代码:@Given("^create a rest document for VHR API$") public void create_a_rest_document_for_VHR_API() throws Throwable { RestAssured.given( spec ) .accept( "application/json" ) .filter( document( "vhrdocument" ) ) .when() .get( props.getVhrrequesturl() + "/vhrData/{vehicleID}", "5VW4T7AU0FM029999" ) .then().log().all(); }
  • 请将 cmets 添加到您的问题中并正确格式化:)
  • 了解您使用的 REST Docs 版本也很有用

标签: spring spring-restdocs


【解决方案1】:

您使用的不是JUnitRestDocumentation,因为它的预期用途。它旨在用作 JUnit 规则,这意味着它应该是一个带有 @Rule 注释的公共字段:

@Rule
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();

成为规则意味着 JUnit 将为每个测试自动调用 restDocumentation,从而允许 Spring REST Docs 设置和拆除特定于测试的上下文。 NullPointerException 正在发生,因为 restDocumentation 尚未以这种方式被调用,因此尚未设置上下文。

您尚未描述如何使用 Cucumber,但如果您使用的是 JUnit runner,您应该能够通过将 restDocumentation 声明为 @Rule-annotated 字段来解决问题,如上所示。如果你不使用它的 JUnit runner,你可能需要使用 Spring REST Docs' ManualRestDocumentation 来代替。 Spring REST Docs 参考文档包含a section,描述了在不使用 JUnit 时如何设置测试。

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,因为我有多个测试类继承了该类,我在其中声明了 JUnitRestDocumentation 实例。我的错误是我使用 @Rule 注释声明了规则。我应该使用@ClassRule 并将实例声明为static

    @ClassRule
    public static JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
    

    【讨论】:

      【解决方案3】:

      它发生在测试 SpockFramework 中,我添加到 pom.xml:

      <dependency>
          <groupId>org.spockframework</groupId>
          <artifactId>spock-junit4</artifactId>
          <scope>test</scope>
      </dependency>
      

      【讨论】:

      • 这是最好的答案。没有junit4 runner 的@Rule 将不起作用。当前 Spock 使用 JUnit 5 引擎,Spock 不支持 JUnit 5 扩展。
      【解决方案4】:

      从 RestAssured 2.x 迁移到 RestAssured 3.1.1 时,我遇到了同样的症状。

      代码库有一种方法来设置 RestAssured 以避免每次测试的重复仪式:

      @Rule
      

      public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();

      @Before
      public void configure_rest_assured() {
          RestAssured.port = springServerPort;
          RestAssured.config = config().objectMapperConfig(
              objectMapperConfig().jackson2ObjectMapperFactory((cls, charset) -> customObjectMapper)
          )
          ...;
          RestAssured.requestSpecification = new RequestSpecBuilder()
              .addRequestSpecification(documentationConfiguration(docRule, ...))
              ...
              .build();
      }
      

      这一直很好,直到我迁移到 3.x。问题是new RequestSpecBuilder() 会将自己附加到默认的静态RestAssured.requestSpecification

      第一个测试通过了,但是当它完成时规则被disposed(after部分),当第二个测试开始运行时,Before方法被链接

      1. 为第一个测试创建的规范(引用第一个测试方法使用的已处置规则)
      2. 为第二个测试创建的规范(引用第二个测试方法的活动规则)

      在运行新测试时等等。 但是当第二个测试运行时,RestAssured 按顺序调用规范,例如数字 1,但由于它引用了已处置的规则(beforeOperation 是在 null 上下文中执行的)

      要修复代码必须清除以前的规范:

      @Before
      public void configure_rest_assured() {
          RestAssured.port = springServerPort;
          RestAssured.config = config().objectMapperConfig(
              objectMapperConfig().jackson2ObjectMapperFactory((cls, charset) -> customObjectMapper)
          )
          ...;
          RestAssured.requestSpecification = null; // avoid the builder to acquire previous specs.
          RestAssured.requestSpecification = new RequestSpecBuilder()
              .addRequestSpecification(documentationConfiguration(docRule, ...))
              ...
              .build();
      }
      

      【讨论】:

        【解决方案5】:

        对于将 cucumber-java-8 与 spring rest docs 和 spring-security 一起使用,以下内容对我有用。

        这是结合@AndyWilkison 上面的答案,但使用黄瓜钩而不是junit 规则。

        public class StepDefs implements En {
        
            @Autowired
            private WebApplicationContext context;
        
            private MockMvc mockMvc;
            private ManualRestDocumentation restDocumentation = new ManualRestDocumentation();
        
            public StepDefs() {
        
                BeforeStep((Scenario scenario) -> {
                    restDocumentation.beforeTest(AuthenticationStepDefs.class, scenario.getName());
                    mockMvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).apply(documentationConfiguration(restDocumentation)).build();
                });
                AfterStep((Scenario scenario) -> {
                    restDocumentation.afterTest();
                });
                When("create a rest document for VHR API", () -> {
                    MvcResult result = mockMvc.perform(/*
                      your normal call here
                    */).
                    .andDo(document("documentation")).
                    .andReturn();
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2018-11-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-02-28
          • 2022-09-30
          • 2021-03-13
          • 1970-01-01
          • 2014-04-27
          相关资源
          最近更新 更多