Giter VIP home page Giter VIP logo

php-swagger-test's Introduction

PHP Swagger Test

Build Status Opensource ByJG GitHub source GitHub license GitHub release Scrutinizer Code Quality

A set of tools for testing your REST calls based on the OpenApi specification using PHPUnit. Currently, this library supports the OpenApi specifications 2.0 (formerly swagger) and 3.0. Some features like callbacks, links and references to external documents/objects weren't implemented.

PHP Swagger Test can help you to test your REST Api. You can use this tool both for Unit Tests or Functional Tests.

This tool reads a previously Swagger JSON file (not YAML) and enables you to test the request and response. You can use the tool "https://github.com/zircote/swagger-php" for creating the JSON file when you are developing your rest API.

The ApiTestCase's assertion process is based on throwing exceptions if some validation or test failed.

Use cases for PHP Swagger test

You can use the Swagger Test library as:

Who is using this library?

Install

composer require "byjg/swagger-test"

Tests

SPEC=swagger php -S 127.0.0.1:8080 tests/rest/app.php &
SPEC=openapi php -S 127.0.0.1:8081 tests/rest/app.php &
vendor/bin/phpunit

Questions?

Please raise your issue on Github issue.

References

This project uses the byjg/webrequest component. It implements the PSR-7 specification, and a HttpClient / MockClient to do the requests. Check it out to get more information.

Dependencies

flowchart TD
    byjg/swagger-test --> byjg/webrequest

Open source ByJG

php-swagger-test's People

Contributors

89409 avatar antonio-rylke-vgl avatar artjomsimon avatar byjg avatar domingojimenez avatar fantom409 avatar gustavoporcides avatar hordev avatar malinink avatar odael avatar steveplevno avatar thepanz avatar ulricheckhardt avatar vitormattos avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

php-swagger-test's Issues

Fatal error while trying to Unset non existing key in array

abstract class SwaggerBody
Fatal error: Cannot unset string offsets in vendor\byjg\swagger-test\src\SwaggerBody.php on line 164

first the key is tested if exist and unset if not exist

if (!array_key_exists($prop, $body)){
    if ($required !== false) {
      throw new NotMatchedException("Required property '$prop' in '$name' not found in object");
   }
// it's useless to unset non existing key 
   unset($body[$prop]);
  continue;
}

Splitting out the request/response validation from the actual request

I'm currently using a little Laravel package I made to make this more "trait" friendly as well as interact directly with Laravel's internal call methods etc. (I hope I haven't bastardised the implementation too much ๐Ÿ˜…)

I ended up doing quite a couple overrides which I think might be useful to actually include back here if you're keen for them.

Most notably: I made my own Requester which splits up the send function into: send, validateRequest and validateResponse

I found that doing failed tests was basically impossible with the current implementation.
Eg:
I want to log in without parsing through an email and get a response of type 422 which exists in the OpenApi/Swagger spec.

It would always fail on the request validation and without splitting them up there was no way I could see to easily test it.

Having a validateRequestFails method (which runs the validate with a try-catch) was suuuuuper useful

Anywhoo, this is more of a "do you want it to move in this direction?" Issue and not a bug report etc :)

Referenced parameters compatibility

Hi,

Is the library compatible with referenced parameters ?

For example in my JSON schema, I have that:

{
  "paths": {
    "/my_path": {
      "get": {
        "summary": "...",
        "description": "...",
        "parameters": [
          {
            "$ref": "#/parameters/my_parameter"
          }
        ]
      }
    }
  },
  "parameters": {
    "my_parameter": {
      "name": "my_parameter",
      "in": "header",
      "description": "...",
      "required": true,
      "type": "string"
    }
  }
}

My test case looks like following :

<?php

namespace MyProject\Tests;

class TestTest extends \ByJG\Swagger\SwaggerTestCase
{
    protected $filePath = 'http://localhost/specifications.json';

    public function test()
    {
        $request = new \ByJG\Swagger\SwaggerRequester();
        $request
            ->withMethod('GET')
            ->withPath('/my_path');


        $this->assertRequest($request);
    }
}

And when I run phpunit I get the following error :

There was 1 error:

1) MyProject\Tests\TestTest::test
Undefined index: in

/home/me/my_project/vendor/byjg/swagger-test/src/SwaggerRequestBody.php:27
/home/me/my_project/vendor/byjg/swagger-test/src/SwaggerRequester.php:158
/home/me/my_project/vendor/byjg/swagger-test/src/SwaggerTestCase.php:88
/home/me/my_project/application/classes/Tests/TestTest.php:17

Unable to run successful tests for the repo (PHPStorm 2020.1)

Hi,

thank you for the package! I I'm working on few fixes to support my openapi3 documentation and I noticed that I can't run successful tests (connection reset on 127.0.0.1) -- servers are started using provided run configurations.

I was able to fix it by changing 127.0.0.1 to localhost in host ( swagger.json and openapi.json).

PHPStorms binds only localhost (on Mac Catalina), then tests can connect to the servers and run tests. Is it working in your environment if you change it to localhost?

Martin

ByJG\ApiTools\Exception\GenericSwaggerException: Not all cases are defined.

Hi,

first: thanks for this great lib!

I get the following error message
ByJG\ApiTools\Exception\GenericSwaggerException: Not all cases are defined. Please open an issue about this. Schema: devices

Test

$request = new ApiRequester();
        $request
            ->withMethod("PUT")
            ->withPath("/api/devices")
            ->withRequestBody(array("devices" => array("action" => "switch", "global_id"=> "DreamboxWohnzimmer", "state"=> "on")));

        $this->assertRequest($request);

Controller

/**
     * Change state(s) of specified devices or notify websocket for changes of specified devices
     * @Rest\Route("/api/devices", methods={"PUT"}, name="api_electricity_device_action"),
     *
     * @SWG\Tag(name="Devices"),
     *
     * @SWG\Parameter(name="body", in="body", description="JSON payload", required=true,
     *     @SWG\Schema(type="object",
     *          @SWG\Property(property="devices", type="array",
     *              @SWG\Items(type="object",
     *                  @SWG\Property(property="action", type="string", enum={"switch", "notify"}, example="switch"),
     *                  @SWG\Property(property="global_id", description="global_id of affected device", type="string",),
     *                  @SWG\Property(property="state", description="new state", type="string"),
     *                  @SWG\Property(property="parameter", description="used for further information (sonos group, yamaha specific input, hue brightness)", type="string", example="brightness"),
     *              )
     *          )
     *      )
     * ),
     * @SWG\Response(response="200", description="Returned when changing states was successful",
     *     @SWG\Schema(type="object",
     *         @SWG\Property(property="global_id", ref=@Model(type=Device::class))
     *     )
     * ),
     *
     * @SWG\Response(response="400", description="Returned when error occured (e.g. parameter missing)",
     *     @SWG\Schema(ref="#/definitions/Error")
     * ),
     *
     * @SWG\Response(response="404", description="Returned when device not found",
     *     @SWG\Schema(ref="#/definitions/Error")
     * )
     */

Did I do something wrong?

Not supported PHPUnit 8.5

Declaration of ByJG\ApiTools\ApiTestCase::setUp() must be compatible with PHPUnit\Framework\TestCase::setUp

PHPUnit\Framework\TestCase:

    /**
     * This method is called before each test.
     */
    protected function setUp(): void
    {
    }

PHP 8 Compatibility

Seems like some dependencies do not have PHP 8 support.

    - byjg/swagger-test[3.1.0, ..., 3.1.2] require byjg/webrequest 2.0.* -> satisfiable by byjg/webrequest[2.0.0, 2.0.1].
    - byjg/webrequest[2.0.0, ..., 2.0.1] require mintware-de/streams 1.0.* -> satisfiable by mintware-de/streams[v1.0.0, v1.0.1].
    - mintware-de/streams[v1.0.0, ..., v1.0.1] require php 5.6.* || ^7.0 -> your php version (8.0.6; overridden via config.platform, same as actual) does not satisfy that requirement.
    - Root composer.json requires byjg/swagger-test 3.1.* -> satisfiable by byjg/swagger-test[3.1.0, 3.1.1, 3.1.2].

This is a request to have these appropriately updated to versions that supports PHP 8.

Nullable does not work with 'oneOf'

OpenAPI 3.0 supports syntax like this:

"category": {
    "oneOf": [
      {
        "$ref": "#/components/schemas/Category"
      }
    ],
    "nullable": true
},

But tests ignors this "nullable" flag.

Guidance on setting up basic functional tests

Hi, I'm excited to have found this library as I've been thinking about building a PHP contract testing library for a while but this appears to share most of the same goals. But despite having read your docs and many of the issues in the queue I'm not quite getting it.

I have a working spec generated dynamically from my application, which is powering a basic Swagger UI page. On the swagger UI there are examples for essentially every parameters and request body, so if you try out any of the endpoints in the UI, whatever the default values are there they will usually produce a successful result if you hit "execute."

I have been hoping to, with a minimum of code, basically just have PHPUnit try each of the tests you can do manually in the SwaggerUI and assert the result matches expected. So, for example, here is one of my paths:

{
  "paths": {
    "/api/1/metastore/schemas/{schema_id}": {
      "get": {
        "operationId": "metastore-get-schema",
        "summary": "Get a specific schema",
        "tags": [
          "Metastore"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/schemaId"
          }
        ],
        "responses": {
          "200": {
            "description": "Ok",
            "content": {
              "application/json": {
                "schema": {
                  "description": "A schema definition, see https://json-schema.org/",
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Schema not found"
          }
        }
      }
    }
  }
}

And here is that parameter:

{
  "components": {
    "parameters": {
      "schemaId": {
        "name": "schema_id",
        "in": "path",
        "description": "The name a of a specific schema. For instance, \"dataset.\"",
        "schema": {
          "type": "string",
          "example": "dataset"
        },
        "required": true,
        "allowEmptyValue": false,
        "examples": {
          "dataset": {
            "value": "dataset"
          },
          "publisher": {
            "value": "publisher"
          },
          "distribution": {
            "value": "distribution"
          },
          "theme": {
            "value": "theme"
          },
          "keyword": {
            "value": "keyword"
          }
        }
      }
    }
  }
}

I've tried this to test it:

  public function testApiGet() {

    $request = new ApiRequester();
    $request
      ->withMethod('GET')
      ->withPath("/api/1/metastore/schemas/{schema_id}");
    $this->assertRequest($request);
  }

I get the error:

1) Drupal\Tests\common\Functional\ApiContractTest::testApiGet
ByJG\ApiTools\Exception\StatusCodeNotMatchedException: Status code not matched: Expected 200, got 404 ->
{
    "message": "Schema {schema_id} not found."
}

Looks like it doesn't automatically plug in the examples in the spec, which is fine, but if I try a path with the path parameter filled in, I get an error I don't really understand:

  public function testApiGet() {

    $request = new ApiRequester();
    $request
      ->withMethod('GET')
      ->withPath("/api/1/metastore/schemas/theme");
    $this->assertRequest($request);
  }
1) Drupal\Tests\common\Functional\ApiContractTest::testApiGet
ByJG\ApiTools\Exception\GenericSwaggerException: Not all cases are defined. Please open an issue about this. Schema: GET 200 /api/1/metastore/schemas/theme

I think I'm pretty close and if I understood what I need to be adding to give the request and assertion everything they need, I could test my whole spec with a minimum of code in my test class, but hoping you can provide a little guidance. Happy to contribute to the docs if that's helpful once I'm a little clearer on the usage, and may publish a helper library if I get this working and find a way to abstract some of these things in a repeatable way.

Drop PHPUnit 4/5 fallback

Is it possible to drop the phpunit4 fallback?

if (!class_exists('\PHPUnit\Framework\TestCase')) {
    class_alias('\PHPUnit_Framework_TestCase', '\PHPUnit\Framework\TestCase');
}

I think there is no reason to keep this. PHPUnit 4 and 5 are no longer supported. see https://phpunit.de/

It would improve the auto completion for phpstorm a lot ;)

A required request body will not fail tests, if no body is given

Hello there, thanks for this great package.

I have the following problem: If I have a required request body (defined in swagger), but non is given in my test, then the test does not fail.
I expected that the test will fail.

This seems to be a bug:
https://github.com/byjg/php-swagger-test/blob/master/src/SwaggerTestCase.php#L80-L82

I think in SwaggerRequestBody the exception should only be thrown if $body is not empty and no parameter body is found.

Library as trait(s) instead of inheritance class

It would be awesome if these tools were provided as traits rather than a class to extend. We have an existing extended TestCase, so I can't use this out of the box and will need to roll my own trait.

Obviously not a big deal, just a suggestion.

issue while consuming json

Hello,
While trying to validate this I got an error in swaggerRequestBody line 27 (version 1.2.5 of your package) :

...
'accounts/create':
    post:
      tags:
        - accounts
      summary: create an account
      description: create an account
      operationId: createAccount
      consumes:
        - application/json
      produces:
        - application/json
      parameters:
        - in: body
          name: name of the account
          schema:
            type: object
            required:
              - wallet_uuid
              - user_uuid
            properties:
              wallet_uuid:
                description: wallet id
                type: string
                format: uuid
                default: '502a1aa3-5239-4d4b-af09-4dc24ac5f034'
              user_uuid:
                description: user id
                type: string
                format: uuid
                default: 'e7f6c18b-8094-4c2c-9987-1be5b7c46678'
      responses:
        '200':
          description: successful operation
          schema:
            $ref: '#/definitions/response_account'
        '204':
          description: Account not found
          schema:
            $ref: '#/definitions/response_error'
        '400':
          description: Invalid ID supplied
          schema:
            $ref: '#/definitions/response_error'

It seems that in swaggerRequestBody you need to change ligne 27 from

                if ( $parameter['required'] === true && empty($body)) {

to

if (isset($parameter['required']) && $parameter['required'] === true && empty($body)) {

Perhaps my json is wrong, you'll be a better judge on that than me.

Regards

Variables in servers object

When I use variables inside URL, the library doesn't make substitution.
This is an example

"servers": [
    {
      "url": "https://{environment}.domain.com{basePath}",
      "description": "My API server",
      "variables": {
        "environment": {
          "enum": [
            "www",
            "stage"
          ],
          "default": "www"
        },
        "basePath": {
          "default": "/api/v2"
        }
      }
    }
]

This is a link on OpenAPI3 specification.

Extra functionality from the Swagger 2.0 spec

Good day,

I'm looking at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#items-object and I notice there's a lot of functionality there which isn't being tested here.

Properties like maximum, minimum, maxLength, minLength, pattern do not seem to be checked. I have noticed that enum is checked, within SwaggerBody->matchString.

Are there any plans to implement the remaining specification? I'm happy to contribute to this project if you're willing to accept my help. I'll put together details of my proposed change and then go from there.

Thanks.

Responses using ref aren't supported

Currently only schema references are supported.
I think we need to do a couple checks here as several swagger objects should be supported.

My use-case for this is pretty simple. Api has a couple of generic responses (404, 401 etc), duplicating all of those for each request isn't ideal, and the perfect usecase for using a ref.

This is where the issue is actually breaking
AbstractBody Line 331:

 if(!isset($schemaArray['$ref']) && isset($schemaArray['content'])) {
            $schemaArray['$ref'] = $schemaArray['content'][key($schemaArray['content'])]['schema']['$ref'];
        }

Api Doc Example:

"/api/user": {
            "get": {
                "tags": [
                    "User"
                ],
                "summary": "Get list of all users",
                "description": "Returns list of users",
                "operationId": "user_index",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/UserIncludes"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "User Collection",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/User"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/ModelNotFound"
                    }
                },
                "security": [
                    {
                        "apiAuth": []
                    }
                ]
            }
        },

nullable value matching

Hi,

I have a definition of an object with property:

"activity": {
  "$ref": "#/definitions/Activity"
},

and this property is not set as required.
When I match a response ({"activity": null}) with that schema, I got an error: "Value of property '#/definitions/Activity' is null, but should be of type 'object'"

yeah, I know, in general, I wrote, that activity is an object, but because OpenApi 2.0 (Swagger) doesn't support any kind of "nullable" definition, do you have any idea how can I test such response?

Match is failing, when property is required and has null value

In case, if property of definition is in required list, and in response that value exists in response, but equals null, match throws exception "Required property not found".
Example:

     /* @SWG\Get(
     *   path="/v1/get",
     *   @SWG\Response(
     *    response=200
     *    @SWG\Schema(
     *      required={"data"}
     *     @SWG\Property(property="data",  type="string"),
     *    ),
     *   )
     * )
*/

Match against response: {"data": null} will throw an exception.

Proposed solution:
SwaggerBody.php on line 116 replace isset with array_key_exists.

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.