This module provides a generic Cucumber vocabulary for testing APIs with swagger-assert4j with dedicated support for Swagger 2.0 to remove some of the technicalities required to define scenarios.
A quick example for the Petstore API at http://petstore.swagger.io, testing of the /pet/findByTags resource could be defined withe following Scenario:
Scenario: Find pet by tags
Given the API running at http://petstore.swagger.io/v2
When a GET request to /pet/findByTags is made
And the tags parameter is test
And the request expects json
Then a 200 response is returned within 50ms
And the response type is json
Using the integrated Swagger support this can be shortened to
Scenario: Find pet by tags
Given the Swagger definition at http://petstore.swagger.io/v2/swagger.json
# deducts path and method from Swagger definition by operationId
When a request to findPetsByTags is made
# deducts type of "tags" parameter (query/path/parameter/body) from Swagger definition
And tags is test
And the request expects json
Then a 200 response is returned within 500ms
And the response type is json
Not a huge difference - but as you can see by the comments the Swagger support removes some of the technicalities; read more about Swagger specific steps below!
Check out the samples submodule for more examples.
If you want to run scenarios as part of a maven build you need to add the following dependency to your pom:
<dependency>
<groupId>io.swagger.assert</groupId>
<artifactId>swagger-assert4j-cucumber-stepdefs</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
(This library has transient dependencies on cucumber-jvm 2.0.0, so no other dependencies are required)
Then create a JUnit runner class that uses Cucumber, add the swagger-assert4j glue/stepdefs, and point it to your feature files, for example:
@RunWith(Cucumber.class)
@CucumberOptions(
plugin = {"pretty", "html:target/cucumber"},
features = {"src/test/resources/cucumber"},
glue = {"io.swagger.assert4j.cucumber" })
public class CucumberTest {
}
If you don’t want to run your tests as part of a java/maven/etc-build or simply want to run them from the command-line you can use swagger-assert4j-cucumber-runner.jar (from the runner module) which includes all required libraries including the Cucumber runtime. Run tests with:
java -jar swagger-assert4j-cucumber-runner-1.0.0-SNAPSHOT.jar <path to feature-files> -p pretty
Internally this will call the regular cucumber.api.cli.Main class with an added -g argument to the included glue-code, all other options are passed as usual, see https://cucumber.io/docs/reference/jvm#cli-runner.
(you will need java8 installed on your path)
If the above two options are too much of a Java hassle for you, you can use the prepackaged docker image available at https://hub.docker.com/r/smartbear/swagger-assert4j-cucumber instead - it packages the above runner and makes it super-easy to run feature files for your APIs without having to install anything (except Docker of course).
For example:
docker run -v /Users/Ole/cucumber:/features smartbear/swagger-assert4j-cucumber -p pretty /features
Here we mounted a local folder containing feature files into a volume named “/features” in the container - and then specify that volume as the source for feature files for the Cucumber Runner, together with the -p pretty argument.
If you add the -Dswagger-assert4j.cucumber.logfolder=...
system property to your command line invocation the runner will write
generated JSON recipes to the specified folder before executing them, for example allowing you
to import them into ReadyAPI for load-testing, monitoring, etc.
The included Cucumber StepDefs (see below) by default execute test recipes using the local open-source execution engine of swagger-assert4j. If you would like to execute your tests via ReadyAPI TestServer instead you will need to download and install TestServer and specify the following system properties when running your tests:
Clone this project and and run
mvn clean install
To build and install the artifacts in your local maven repository - the packaged jar is created in the root target folder.
The included StepDefs for API testing adds the following vocabulary:
"""
{ "id" : "123" }
"""
”
"""
"id" : "123"
"""
”
"""
.*testing.*
"""
”Below is the swaggerhub.feature in the samples submodule.
Feature: SwaggerHub REST API
Background:
Given the Swagger definition at https://api.swaggerhub.com/apis/swagger-hub/registry-api/1.0.10
Scenario: Default API Listing
When a request to searchApis is made
Then the response is a list of APIs in APIs.json format
Scenario: Owner API Listing
When a request to getOwnerApis is made
And owner is swagger-hub
Then the response is a list of APIs in APIs.json format
Scenario: API Version Listing
When a request to getApiVersions is made
And owner is swagger-hub
And api is registry-api
Then the response is a list of API versions in APIs.json format
And the response body contains
"""
"url":"/apis/swagger-hub/registry-api"
"""
Scenario Outline: API Retrieval
When a request to getDefinition is made
And owner is <owner>
And api is <api>
And version is <version>
Then a 200 response is returned within 500ms
And the response type is json
And the response body contains
"""
"description":"<description>"
"""
Examples:
| owner | api | version | description |
| swagger-hub | registry-api | 1.0.10 | The registry API for SwaggerHub |
| fehguy | sonos-api | 1.0.0 | A REST API for the Sonos platform |
You can extend the included REST API testing vocabulary by providing custom StepDefs that tie into the underlying swagger-assert4j recipe generation. Do this as follows (a complete example is shown below):
Internally the actual recipe gets created and sent to the execution engine first in a Cucumber @After handler
If you want to delegate some of your custom vocabulary to the existing RestStepDefs you can inject them into your custom StepDefs constructor also and then use it as needed.
The below class shows all the above concepts (this class is in the samples module):
package com.smartbear.cucumber.samples.extension;
import CucumberRecipeBuilder;
import RestStepDefs;
import cucumber.api.java.en.Given;
import cucumber.runtime.java.guice.ScenarioScoped;
import javax.inject.Inject;
@ScenarioScoped
public class CustomStepDefs {
private final CucumberRecipeBuilder recipeBuilder;
private final RestStepDefs restStepDefs;
@Inject
public CustomStepDefs(CucumberRecipeBuilder recipeBuilder, RestStepDefs restStepDefs ){
this.recipeBuilder = recipeBuilder;
this.restStepDefs = restStepDefs;
}
/**
* Provide an alternative vocabulary for specifying an API endpoint
*/
@Given("^an endpoint of (.*)$")
public void anEndpointOf( String endpoint ) throws Throwable {
restStepDefs.setEndpoint( endpoint );
}
}
To get this used during execution you will need to
For example (line-breaks and comments added for readability):
java -cp modules/samples/target/swagger-assert4j-cucumber-samples-1.0.0-SNAPSHOT.jar: // the extension jar
modules/runner/target/swagger-assert4j-cucumber-runner-1.0.0-SNAPSHOT.jar // the runner jar
io.swagger.assert4j.cucumber.CucumberRunner // the runner class
-g com.smartbear.cucumber.samples.extension // the extension package argument
modules/samples/src/test/resources/cucumber // the features folder
If you’ve found a bug or are missing some kind of vocabulary/functionality/etc please contribute or open an issue!