youritservices / mock-server-bundle
Symfony commands for loading API mocks into MockServer
Requires
- php: ^7.4|^8.0
- ext-json: *
- nesbot/carbon: ^2.61
- symfony/config: ^5.4|^6.0
- symfony/dependency-injection: ^5.4|^6.0
- symfony/http-client: ^5.4.|^6.0
- symfony/http-kernel: ^5.4|^6.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.14
- mikey179/vfsstream: ^1.6
- phpstan/phpstan: ^1.10
- phpstan/phpstan-phpunit: ^1.3
- phpstan/phpstan-symfony: ^1.2
- phpunit/phpunit: ^9.5
- rregeer/phpunit-coverage-check: ^0.3.1
- slevomat/coding-standard: ^8.3
- squizlabs/php_codesniffer: ^3.7
- symfony/dotenv: ^5.4|^6.0
- symfony/phpunit-bridge: ^5.4|^6.0
README
The aim of Mock Server Bundle is to make mocking remote API calls easier during both automated testing and local development work, removing the need for remote API mocking code in the application itself, and ensuring that the API calls are made outside the system under test.
This bundle makes use of MockServer to provide the remote mock API (via a Docker container) and adds Symfony commands to load and reset mock API data into this system.
The mocks themselves can currently use the following formats:
- JSON
- JSON:API
- SOAP
along with the following methods:
- GET
- DELETE
- PATCH
- POST
The bundle takes the provided mock files (see below) and assembles them into a suitable request for MockServer, allowing developers or testers to simply add the expected request and response payloads (for example, by copying existing payloads from actual API calls), without having to write code to implement them.
Installation
The bundle uses a contrib recipe, so you will either need to enable that during install, or add the option to your composer config with:
composer config extra.symfony.allow-contrib true
Install the package with:
composer require youritservices/mock-server-bundle --dev
Enable the bundle
If you're not using Symfony Flex, you'll need to enable the bundle by adding the following line in the
config/bundles.php
file of your project:
<?php
declare(strict_types=1);
return [
...
YourITServices\MockServerBundle\MockServerBundle::class => ['dev' => true, 'test' => true],
...
];
Configuration
Edit the config/packages/mock_server.yaml
file, setting the values as appropriate for your environment. The file and
environment variable MOCK_SERVER_HOST
will have been added to your .env
file by the flex recipe.
# config/packages/mock_server.yaml
when@test: &test
mock_server:
host_url: '%env(MOCK_SERVER_HOST)%'
mocks_directory: '%kernel.project_dir%/tests/apiMocks'
when@dev: *test
Parameters:
host_url
Required
The URL for the MockServer Docker container set up in your docker-compose.yml
mocks_directory
Required
The path to the root of the API mocks you want to load.
MockServer Service
The commands make use of MockServer, so this needs to be available to your project, with the easiest being via a service
defined in docker-compose.yml
.
# docker-compose.yml
version: '3.9'
services:
mock-api:
image: mockserver/mockserver:5.15.0
ports:
- "1080:1080"
environment:
JVM_OPTIONS: -Dmockserver.enableCORSForAllResponses=true
MockServer provides a dashboard, so you can view the loaded mocks, as well as the requested made against the service. If you defined the service as above, this can be accessed via http://mock-api:1080/mockserver/dashboard
Usage
API mocks
The API mocks can be stored in any directory structure under mocks_directory, allowing you to organize your mocks how you see fit.
Each mock consists of a number of files, depending on both the format involved and the HTTP verb used, as detailed below.
The mocks are loaded in directory order, and each directory is ordered by the sequence number of the file(s) contained in that directory. MockServer processes the loaded mocks in the order they are created, so default or fallback responses should be sequenced after more specific responses.
URL
The URL file is used for a JSON or JSON:API based mock and follows the file naming convention:
<sequence number>.<description>.url.txt
The file contains the following contents:
<status code> <verb> <url encoded path> <format> <response time (optional)>
SOAP
The soap file is used for a SOAP based mock and follows the file naming convention:
<sequence number>.<description>.soap.txt
The file contains the following contents:
<status code> <verb> <url encoded path> <SOAP action> <response time (optional)>
Request
This file contains the request body (where required) in the expected format (json or xml), exactly as it would be sent to the remote API and follows the file naming convention:
<sequence number>.<description>.request.<format>
Response
This file contains the response body in the expected format (json or xml), exactly as it would be sent by the remote API in response to the request, and follows the file naming convention:
<sequence number>.<description>.response.<format>
Examples
GET (JSON)
1.sending-postcode-with-available-addresses.url.txt
200 GET /v1/autocomplete/addresses/paf_1/gbr?api_key=TestAddressApiKey JSON 500ms
1.sending-postcode-with-available-addresses.response.json
{
"result": [
{
"line_1": "1 Test Street",
"line_2": "Test Line 2",
"line_3": "Test Line 3",
"post_town": "TOWN",
"traditional_county": "Test County",
"postal_county": "Test County",
"postcode": "POST C01",
"id": "paf_1"
}
],
"code": 2000,
"message": "Success",
"limit": 100,
"page": 0,
"total": 1
}
POST (JSON:API)
1.create-customer.url.txt
201 POST /api/v1/test JSON:API 100ms
1.create-customer.request.json
{
"data": {
"type": "customers",
"attributes": {
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com"
}
}
}
1.create-customer.response.json
{
"jsonapi": {
"version": "1.0"
},
"meta": {
"version": "0.1.0"
},
"data": {
"type": "customer",
"id": "1",
"attributes": []
}
}
POST (SOAP)
1.validate-address.soap.txt
200 POST /services/ValidateAddressServiceSoap ValidateAddressRequest 100ms
1.validate-address.request.xml
<?xml version="1.0" encoding="UTF-8"?>
<soap-env:envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="https://xmlns.example.com/Address/ValidateAddress">
<soap-env:header></soap-env:header>
<soap-env:body>
<ns1:ValidateAddressRequest>
</ns1:ValidateAddressRequest>
</soap-env:body>
</soap-env:envelope>
1.validate-address.response.xml
<?xml version="1.0" encoding="UTF-8"?>
<soap-env:envelope xmlns:soap-env="http://www.w3.org/2003/05/soap-envelope">
<soap-env:body>
<ns0:ValidateAddressResponse xmlns:ns0="https://xmlns.example.com/Address/ValidateAddress">
</ns0:ValidateAddressResponse>
</soap-env:body>
</soap-env:envelope>
Commands
Load mocks
This loads all the available mocks in the configured mocks_directory
bin/console mockserver:load
Reset / remove mocks
This resets / removes all the currently loaded mocks, normally used before a load to ensure only the current mocks are loaded / available.
bin/console mockserver:reset
Development
The bundle comes with a Makefile to allow for an easy development environment setup. Simply clone the repository,
ensure the requirements are met, then run make up
Requirements
Basic Commands
Start all Docker containers
make up
Stop all Docker containers
make down
Clean slate (remove vendor and rebuild containers)
make rebuild
Run all tests before pushing to remote branch and triggering CI pipeline
make pre-push
All available make commands
make help