Git Product home page Git Product logo

assertj-swagger's Introduction

assertj-swagger

Build Status Coverage Status Apache License 2

Overview

assertj-swagger is a assertj library which compares a contract-first Swagger YAML/JSON file with a code-first Swagger JSON output (e.g. from springfox or JAX-RS Swagger). assertj-swagger allows to validate that the API implementation is in compliance with a contract specification for two test patterns: Documentation Driven Contracts and Consumer Driven Contracts.

The Documentation Driven Contracts test pattern, useful for public APIs, validates using #isEqualTo and will validate that the design first documentation contract matches the implementation in its entirety.

The Consumer Driven Contracts test pattern, useful for internal microservice APIs, validates using #satisfiesContract and will validate that the implementation provides, at minimum, the requirements of the design first consumer contract. This pattern allows for extension points in the API resources, resource methods, and models.

The library supports the Swagger v2.0 specification. assertj-swagger compares Swagger objects like Paths, Parameters and Definitions. It does not compare unimportant Swagger objects like info, descriptions or summaries.

Usage guide

Adding assertj-swagger to your project

The project is published in JCenter and Maven Central.

Maven

<repositories>
    <repository>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
        <id>central</id>
        <name>bintray</name>
        <url>http://jcenter.bintray.com</url>
    </repository>
</repositories>

<dependency>
    <groupId>io.github.vijayvepa</groupId>
    <artifactId>assertj-swagger</artifactId>
    <version>0.9.2</version>
</dependency>

Gradle

repositories {
    mavenCentral()
}

compile "io.github.vijayvepa:assertj-swagger:0.9.2"

Using assertj-swagger in an integration test

Using assertj-swagger is simple. For example, if you are using Spring Boot and springfox or JAX-RS Swagger, you can validate your Swagger JSON in an integration test.

The following code sample shows how to validate an API using the Documentation Driven Contract test pattern:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@IntegrationTest
@WebAppConfiguration
public class AssertjSwaggerDocumentationDrivenTest {
    @Test
    public void validateThatImplementationMatchesDocumentationSpecification(){
        String designFirstSwagger = SwaggerAssertTest.class.getResource("/swagger.yaml").getPath();
        SwaggerAssertions.assertThat("http://localhost:8080/v2/api-docs")
            .isEqualTo(designFirstSwagger);
    }
}

The following code sample shows how to validate an API using the Consumer Driven Contract test pattern:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@IntegrationTest
@WebAppConfiguration
public class AssertjSwaggerConsumerDrivenTest {
    @Test
    public void validateThatImplementationSatisfiesConsumerSpecification(){
        String designFirstSwagger = SwaggerAssertTest.class.getResource("/swagger-consumer1.yaml").getPath();
        SwaggerAssertions.assertThat("http://localhost:8080/v2/api-docs")
            .satisfiesContract(designFirstSwagger);
    }
}

Example output

For Documentation Driven Contract tests, Assertj-swagger fails a test if it finds differences between the implementation and the specification.

The following 4 assertions failed:
1) [Checking Paths]
Expecting:
  <["/api/pet", "/api/pet/findByStatus", "/api/pet/findByTags", "/api/pet/{petId}", "/api/store/order", "/api/store/order/{orderId}", "/api/user", "/api/user/createWithArray", "/api/user/createWithList", "/api/user/login", "/api/user/logout", "/api/user/{username}"]>
to contain only:
  <["/pets", "/pets/findByStatus", "/pets/findByTags", "/pets/{petId}", "/stores/order", "/stores/order/{orderId}", "/users", "/users/createWithArray", "/users/createWithList", "/users/login", "/users/logout", "/users/{username}"]>
elements not found:
  <["/pets/findByTags", "/users/logout", "/users", "/stores/order", "/users/createWithArray", "/pets", "/users/createWithList", "/pets/findByStatus", "/pets/{petId}", "/users/{username}", "/stores/order/{orderId}", "/users/login"]>
and elements not expected:
  <["/api/store/order", "/api/user", "/api/user/createWithList", "/api/pet", "/api/pet/findByTags", "/api/user/createWithArray", "/api/user/login", "/api/pet/{petId}", "/api/store/order/{orderId}", "/api/user/{username}", "/api/pet/findByStatus", "/api/user/logout"]>

2) [Checking properties of definition 'Order']
Expecting:
  <["complete", "id", "identifier", "petId", "quantity", "shipDate", "status"]>
to contain only:
  <["id", "petId", "quantity", "shipDate", "status", "complete"]>
elements not found:
  <[]>
and elements not expected:
  <["identifier"]>

3) [Checking properties of definition 'User']
Expecting:
  <["email", "firstName", "id", "identifier", "lastName", "password", "phone", "userStatus", "username"]>
to contain only:
  <["id", "username", "firstName", "lastName", "email", "password", "phone", "userStatus"]>
elements not found:
  <[]>
and elements not expected:
  <["identifier"]>

4) [Checking properties of definition 'Pet']
Expecting:
  <["category", "id", "identifier", "name", "photoUrls", "status", "tags"]>
to contain only:
  <["id", "category", "name", "photoUrls", "tags", "status"]>
elements not found:
  <[]>
and elements not expected:
  <["identifier"]>

For Consumer Driven Contract tests, Assertj-swagger fails a test if it finds missing resources, methods, models, or properties in the implementation which are required by the consumer specification.

The following 4 assertions failed:
1) [Checking Paths]
Expecting:
 <["/pets", "/pets/findByStatus", "/pets/findByTags", "/pets/{petId}", "/stores/order", "/stores/order/{orderId}", "/users", "/users/createWithArray", "/users/createWithList", "/users/login", "/users/logout", "/users/{username}"]>
to contain:
 <["/animals/{animalId}", "/pets", "/pets/findByStatus", "/pets/{petId}"]>
but could not find:
 <["/animals/{animalId}"]>

2) [Checking Definitions]
Expecting:
 <["User", "Category", "Pet", "Tag", "Order"]>
to contain:
 <["Category", "Pet", "Animal", "Tag"]>
but could not find:
 <["Animal"]>

3) [Checking properties of definition 'Pet']
Expecting:
 <["id", "category", "name", "photoUrls", "tags", "status"]>
to contain:
 <["photoUrls", "extraProperty", "name", "id", "category", "tags", "status"]>
but could not find:
 <["extraProperty"]>

4) [Checking property 'extraProperty' of definition 'Pet']
Expecting actual not to be null

Using assertj-swagger in a unit test

If you are using the spring-framework and springfox, Spring’s MVC Test framework can also be used to validate the Swagger JSON output against your contract-first Swagger specification.
That way you can make sure that the implementation is in compliance with the design specification.

The following code sample shows how to write a unit test using the Documentation Driven Contract test pattern:

@Test
public void validateThatImplementationFitsDesignSpecification() throws Exception {
    String designFirstDocumentationSwaggerLocation = Swagger2MarkupTest.class.getResource("/swagger.yaml").getPath();

    MvcResult mvcResult = this.mockMvc.perform(get("/v2/api-docs")
            .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andReturn();

    String springfoxSwaggerJson = mvcResult.getResponse().getContentAsString();
    SwaggerAssertions.assertThat(new SwaggerParser().parse(springfoxSwaggerJson)).isEqualTo(designFirstDocumentationSwaggerLocation);
}

The following code sample shows how to write a unit test using the Consumer Driven Contract test pattern:

@Test
public void validateThatImplementationFitsDesignSpecification() throws Exception {
    String designFirstConsumerSwaggerLocation = Swagger2MarkupTest.class.getResource("/swagger-consumer1.yaml").getPath();

    MvcResult mvcResult = this.mockMvc.perform(get("/v2/api-docs")
            .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andReturn();

    String springfoxSwaggerJson = mvcResult.getResponse().getContentAsString();
    SwaggerAssertions.assertThat(new SwaggerParser().parse(springfoxSwaggerJson)).satisfiesContract(designFirstConsumerSwaggerLocation);
}

Customizing assertj-swagger’s behaviour

For most use cases, the default behaviour will be sufficient. However, you can override the default behaviour in various ways by placing a Java property file, /assertj-swagger.properties, at the root of your classpath. It is also possible to override the configuration in your tests; construct an instance of the SwaggerAssert class with a custom configuration if this is required.

The following overrides are available:

Disable various types of checks which are enabled by default

  • assertj.swagger.validateDefinitions=false: disable all validation of definitions

    • assertj.swagger.validateProperties=false: disable validation of properties of definitions

      • assertj.swagger.validateRefProperties=false: disable validation of reference ($ref) properties of definitions

      • assertj.swagger.validateArrayProperties=false: disable validation of array properties of definitions

      • assertj.swagger.validateByteArrayProperties=false: disable validation of byte-array properties of definitions

      • assertj.swagger.validateStringProperties=false: disable validation of string properties of definitions

    • assertj.swagger.validateModels=false: disable validation of models

  • assertj.swagger.validatePaths=false: disable all validation of endpoint definitions

  • assertj.swagger.validateResponseWithStrictlyMatch=false: allow actual contract return extra return code

Enable various types of checks which are disabled by default

The following settings are disabled by default, as they will cause schema comparisions to be too brittle for many users. They can be enabled if required.

  • assertj.swagger.validateInfo=true: enable comparison of the info section

  • assertj.swagger.validateVersion=true: enable comparison of the schema version numbers

Disable checks for certain paths or definitions in 'actual' schema

This feature is useful in development situations, where you have written a contract-first schema by hand, and are validating a contract-last schema generated by a partially-implemented API.

To ignore unimplemented endpoints, try something like:

assertj.swagger.pathsToIgnoreInExpected=\
   /v1/friends/{id},\
   /v1/groups/{groupId}

To ignore unimplemented definitions, use something like:

assertj.swagger.definitionsToIgnoreInExpected=\
   Foo,\
   Bar

To ignore unimplemented properties, use something like:

assertj.swagger.propertiesToIgnoreInExpected=\
   Foo.prop1,\
   Bar.prop2

Comparing expected and actual paths in schemas

It is occasionally useful to be able to compare schemas, where due to limitations in tools and libraries, endpoint
paths don’t align. Specifying a basePath setting in your design-first schema here won’t work — it’s only used by
Swagger tooling to generate paths at runtime, and does not form part of the logical pathname of your endpoints.
For instance, in your design-first schema, you may specify a set of endpoints and a basePath, while your generated
schema (generated from, say, Springfox) has a common prefix prepended on the endpoint paths; e.g.:

/pets/findByStatus       ! design-first schema

and

/v2/pets/findByStatus    ! actual schema

To ensure that assertj-swagger is comparing like-with-like in this situation, you could use the following in your
configuration file:

assertj.swagger.pathsPrependExpected=/v2

License

Copyright 2015 Robert Winkler

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Release Steps

Note
These steps are for the maintainer.

Run the following task

---
./gradlew publishMavenJavaPublicationToMavenCentralRepository
---

See Releasing Deployment from OSSRH for the next steps.

assertj-swagger's People

Contributors

robwin avatar benfowler avatar marcelstoer avatar hsvabek avatar zacyang avatar jsfrench avatar aabutaleb avatar alan-segar-tr avatar alexeytokar avatar oloo avatar askoning avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.