无法使用Cucumber生成Spring rest文档

时间:2017-11-21 21:20:25

标签: spring spring-restdocs

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

错误讯息:

>>> fo={'engine': 'diesel'}
>>> filter(lambda d: all(d[e]==fo[e] for e in fo if e in d), inv)
[{'color': 'red', 'engine': 'diesel', 'type': 'car'}, {'color': 'red', 'engine': 'diesel', 'type': 'truck'}]

代码:

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 );
}

5 个答案:

答案 0 :(得分:3)

您没有使用JUnitRestDocumentation,因为它打算使用。它被设计用作JUnit规则,这意味着它应该是一个用@Rule注释的公共字段:

@Rule
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();

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

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

答案 1 :(得分:3)

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

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

从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

第一个测试通过了,但是当规则完成后,它被处置(后一部分),当第二个测试开始运行时,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();
}

答案 4 :(得分:0)

对于将cucumber-java-8与spring rest文档和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();
        }
    }
}