ravi
ravi

Reputation: 81

Unable to generate the Spring rest docs using Cucumber

I am trying to test spring rest documentation for rest API for our services using spring cucumber jvm but end up with a null pointer exeception when I try to execute the scenario, as the framework is not able to intialize the Junit context.

Error Message:

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)

Code:

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

Step definition code:

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

Upvotes: 3

Views: 1286

Answers (5)

Ivan
Ivan

Reputation: 2858

it happened with test SpockFramework, and i added to pom.xml:

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

Upvotes: 2

Wes
Wes

Reputation: 7047

For using cucumber-java-8 with spring rest docs and spring-security the following worked for me.

This is combining @AndyWilkison's answer from above but using the cucumber hooks instead of junit rules.

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

Upvotes: 0

bric3
bric3

Reputation: 42223

I had the same symptoms when migrating from RestAssured 2.x to RestAssured 3.1.1.

The codebase had a way to setup RestAssured in order to avoid repetitive ceremony for every tests :

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

This was working well, until I migrated to 3.x. The issue was that new RequestSpecBuilder() will append itself to the default static RestAssured.requestSpecification.

The first test passed, but when it finished the rule was disposed (the after part), when the second test started to ran, the Before method was chaining

  1. the specification created for the first test (referencing the disposed rule used by the first test method)
  2. the specification created for the second test (referencing the active rule for second test method)

And so on as new tests are ran. But when the second test is run RestAssured invoke specification in order, e.g. the number 1, but since it was referencing a disposed rule (the beforeOperation was executed on a null context)

To fix that the code had to clear the previous specifications :

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

Upvotes: 0

Muhammad Gelbana
Muhammad Gelbana

Reputation: 4000

I had the same problem because I had multiple test class inheriting the class, in which I declared the JUnitRestDocumentation instance. My mistake was that I declared the rule using the @Rule annotation. I should have used @ClassRule and declared the instance as static.

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

Upvotes: 4

Andy Wilkinson
Andy Wilkinson

Reputation: 116051

You aren't using JUnitRestDocumentation as it's intended to be used. It's designed to be used as a JUnit rule which means it should be a public field annotated with @Rule:

@Rule
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();

Being a rule means that JUnit will automatically call restDocumentation for each test, allowing Spring REST Docs to set up and tear down the test-specific context. The NullPointerException is occurring because restDocumentation hasn't been called in this way and, therefore, the context hasn't been set up.

You haven't described how you're using Cucumber, but if you're using it's JUnit runner you should be able to fix the problem by declaring restDocumentation as a @Rule-annotated field as shown above. If you're not using its JUnit runner, you may need to use Spring REST Docs' ManualRestDocumentation instead. The Spring REST Docs reference documentation contains a section that describes how to set up your tests when you're not using JUnit.

Upvotes: 4

Related Questions