All Projects → ciareis → bypass

ciareis / bypass

Licence: MIT license
↪️ Bypass for PHP creates a custom HTTP Server to return predefined responses to client requests. Useful for tests with Pest PHP or PHPUnit.

Programming Languages

PHP
23972 projects - #3 most used programming language

Projects that are alternatives of or similar to bypass

Charlatan
Create fake data in R
Stars: ✭ 209 (+113.27%)
Mutual labels:  faker
jRand
A Java library to generate random data for all sorts of things. Java random data faker
Stars: ✭ 27 (-72.45%)
Mutual labels:  faker
faker
Random fake data and struct generator for Go.
Stars: ✭ 67 (-31.63%)
Mutual labels:  faker
Foundry
A model factory library for creating expressive, auto-completable, on-demand dev/test fixtures with Symfony and Doctrine.
Stars: ✭ 216 (+120.41%)
Mutual labels:  faker
dummy
Run mock server based off an API contract with one command
Stars: ✭ 170 (+73.47%)
Mutual labels:  faker
randomdata
TYPO3 extensions to generate new random data or replace existing data with random data
Stars: ✭ 14 (-85.71%)
Mutual labels:  faker
Alice
Expressive fixtures generator
Stars: ✭ 2,289 (+2235.71%)
Mutual labels:  faker
apollobank
A full stack GraphQL banking application using React, Node & TypeScript.
Stars: ✭ 203 (+107.14%)
Mutual labels:  faker
CRC-manipulator
Change CRC checksums of your files.
Stars: ✭ 73 (-25.51%)
Mutual labels:  faker
Paw-FakerDynamicValue
A dynamic value extension for Paw using Faker to generate data
Stars: ✭ 16 (-83.67%)
Mutual labels:  faker
Node Mock Server
File based Node REST API mock server
Stars: ✭ 225 (+129.59%)
Mutual labels:  faker
Casual
Fake data generator for javascript
Stars: ✭ 2,793 (+2750%)
Mutual labels:  faker
ImNotSpider
浏览器User Agent生成器
Stars: ✭ 17 (-82.65%)
Mutual labels:  faker
Joal
An open source command line RatioMaster with an optional WebUI.
Stars: ✭ 213 (+117.35%)
Mutual labels:  faker
swagger-faker
Generate mocker services automatically through Swagger or OpenAPI.
Stars: ✭ 26 (-73.47%)
Mutual labels:  faker
Fake Apache Log Generator
Generate a boatload of Fake Apache Log files very quickly
Stars: ✭ 207 (+111.22%)
Mutual labels:  faker
mockingbird
🐦 Decorator Powered TypeScript Library for Creating Mocks
Stars: ✭ 70 (-28.57%)
Mutual labels:  faker
jedi-faker
Faker extension for Star Wars junkie
Stars: ✭ 15 (-84.69%)
Mutual labels:  faker
FakerDotNet
A .NET port of the Ruby faker gem
Stars: ✭ 15 (-84.69%)
Mutual labels:  faker
fake-numbers
Generate fake, valid numbers. Check if a number is valid. Support a lot of different numbers: Credit card, EAN, ISBN, RTN, VIN, etc.
Stars: ✭ 51 (-47.96%)
Mutual labels:  faker

Bypass Logo

Bypass for PHP

About | Installation | Writing Tests | Examples | Credits | Inspired

US flag in base64 BR flag in base64

Tests GitHub tag (latest by date) Packagist Downloads Packagist License Last Updated


About

Bypass for PHP provides a quick way to create a custom HTTP Server to return predefined responses to client requests.

This is useful in tests when your application make requests to external services, and you need to simulate different situations like returning specific data or unexpected server errors.


Installation

📌 Bypass requires PHP 8.0+.

To install via composer, run the following command:

composer require --dev ciareis/bypass

Video demo

Pest and Bypass

Writing Tests

Content

📝 Note: If you wish to view full codes, head to the Examples section.

1. Open a Bypass Server

To write a test, first open a Bypass server:

//Opens a new Bypass server
$bypass = Bypass::open();

Bypass will always run at http://localhost listening to a random port number.

If needed, a port can be specified passing it as an argument (int) $port:

//Opens a new Bypass using port 8081
$bypass = Bypass::open(8081);

2. Bypass URL and Port

The Bypass server URL can be retrieved with getBaseUrl():

$bypassUrl = $bypass->getBaseUrl(); //http://localhost:16819

If you need to retrieve only the port number, use the getPort() method:

$bypassPort = $bypass->getPort(); //16819

3. Routes

Bypass serves two types of routes: The Standard Route, which can return a text body content and the File Route, which returns a binary file.

When running your tests, you will inform Bypass routes to Application or Service, making it access Bypass URLs instead of the real-world URLs.

3.1 Standard Route

use Ciareis\Bypass\Bypass;

//Json body
$body = '{"username": "john", "name": "John Smith", "total": 1250}';

//Route retuning the JSON body with HTTP Status 200
$bypass->addRoute(method: 'GET', uri: '/v1/demo/john', status: 200, body: $body);

//Instantiates a DemoService class
$service = new DemoService();

//Consumes the service using the Bypass URL
$response = $service->setBaseUrl($bypass->getBaseUrl())
  ->getTotalByUser('john');

//Your test assertions here...

The method addRoute() accepts the following parameters:

Parameter Type Description
HTTP Method string $method HTTP Request Method (GET/POST/PUT/PATCH/DELETE)
URI string $uri URI to be served by Bypass
Status int $status HTTP Status Code to be returned by Bypass (default: 200)
Body string|array $body Body to be served by Bypass (optional)
Times int $times How many times the route should be called (default: 1)

3.2 File Route

use Ciareis\Bypass\Bypass;

//Reads a PDF file
$demoFile = \file_get_contents('storage/pdfs/demo.pdf');

//File Route returning a binary file with HTTP Status 200
$bypass->addFileRoute(method: 'GET', uri: '/v1/myfile', status: 200, file: $demoFile);

//Instantiates a DemoService class
$service = new DemoService();

//Consumes the service using the Bypass URL
$response = $service->setBaseUrl($bypass->getBaseUrl())
  ->getPdf();

//Your test assertions here...

The method addFileRoute() accepts the following parameters:

Parameter Type Description
HTTP Method string $method HTTP Request Method (GET/POST/PUT/PATCH/DELETE)
URI string $uri URI to be served by Bypass
Status int $status HTTP Status Code to be returned by Bypass (default: 200)
File binary $file Binary file to be served by Bypass
Times int $times How many times the route should be called (default: 1)

3.3 Bypass Serve and Route Helpers

Bypass comes with a variety of convenient shortcuts to the most-common-used HTTP requests.

These shortcuts are called "Route Helpers" and are served automatically at a random port using Bypass::serve().

When serving Route Helpers, there is no need to call Bypass::open().

Example:

use Ciareis\Bypass\Bypass;
use Ciareis\Bypass\Route;

//Create and serve routes
$bypass = Bypass::serve(
  Route::ok(uri: '/v1/demo/john', body: ['username' => 'john', 'name' => 'John Smith', 'total' => 1250]), //method GET, status 200
  Route::notFound(uri: '/v1/demo/wally') //method GET, status 404
);

//Instantiates a DemoService class
$service = new DemoService();
$service->setBaseUrl($bypass->getBaseUrl());

//Consumes the "OK (200)" route
$responseOk = $service->getTotalByUser('john'); //200 - OK with total => 1250

//Consumes the "Not Found (404)" route
$responseNotFound = $service->getTotalByUser('wally'); //404 - Not found

//Your test assertions here...

In the example above Bypasss serves two routes: A URL accessible by method GET returning a JSON body with status 200, and a second route URL accessible by method GET and returning status 404.

Route Helpers

Route Helper Default Method HTTP Status Body Common usage
Route::ok() GET 200 optional (string|array) Request was successful
Route::created() POST 201 optional (string|array) Response to a POST request which resulted in a creation
Route::badRequest() POST 400 optional (string|array) Something can't be parsed (ex: wrong parameter)
Route::unauthorized() GET 401 optional (string|array) Not logged in
Route::forbidden() GET 403 optional (string|array) Logged in but trying to request a restricted resource (without permission)
Route::notFound() GET 404 optional (string|array) URL or resource does not exist
Route::notAllowed() GET 405 optional (string|array) Method not allowed
Route::validationFailed() POST 422 optional (string|array) Data sent does not satisfy validation rules
Route::tooMany() GET 429 optional (string|array) Request rejected due to server limitation
Route::serverError() GET 500 optional (string|array) General indication that something is wrong on the server side

You may also adjust the helpers to your needs by passing parameters:

Parameter Type Description
URI string $uri URI to be served by Bypass
Body string|array $body Body to be served by Bypass (optional)
HTTP Method string $method HTTP Request Method (GET/POST/PUT/PATCH/DELETE)
Times int $times How many times the route should be called (default: 1)

In the example below, you can see the Helper Route::badRequest using method GET instead of its default method POST.

use Ciareis\Bypass\Bypass;
use Ciareis\Bypass\Route;

Bypass::serve(
  Route::badRequest(uri: '/v1/users?filter=foo', body: ['error' => 'Filter parameter foo is not allowed.'], method: 'GET')
);

📝 Note: Custom routes can be created using a Standard Route in case something you need is not covered by the Helpers.

4. Asserting Route Calling

You may need to assert that a route was called at least one or multiple times.

The method assertRoutes() will return a RouteNotCalledException if a route was NOT called as many times as defined in the $times parameter.

If you need to assert that a route is NOT being called by your service, set the parameter $times = 0

//Json body
$body = '{"username": "john", "name": "John Smith", "total": 1250}';

//Defines a route which must be called two times
$bypass->addRoute(method: 'GET', uri: '/v1/demo/john', status: 200, body: $body, times: 2);

//Instantiates a DemoService class
$service = new DemoService();

//Consumes the service using the Bypass URL
$response = $service->setBaseUrl($bypass->getBaseUrl())
  ->getTotalByUser('john');

$bypass->assertRoutes();

//Your test assertions here...

5. Stop or shut down

Bypass will automatically stop its server once your test is done running.

The Bypass server can be stopped or shut down at any point with the following methods:

To stop: $bypass->stop();

To shut down: $bypass->down();

Examples

Use case

To better illustrate Bypass usage, imagine you need to write a test for a service called TotalScoreService. This service calculates the total game score of a given username. To get the score is obtained making external request to a fictitious API at emtudo-games.com/v1/score/::USERNAME::. The API returns HTTP Status 200 and a JSON body with a list of games:

{
  "games": [
    {
      "id": 1,
      "points": 25
    },
    {
      "id": 2,
      "points": 10
    }
  ],
  "is_active": true
}
use Ciareis\Bypass\Bypass;

//Opens a new Bypass server
$bypass = Bypass::open();

//Retrieves the Bypass URL
$bypassUrl = $bypass->getBaseUrl();

//Json body
$body = '{"games":[{"id":1, "name":"game 1","points":25},{"id":2, "name":"game 2","points":10}],"is_active":true}';

//Defines a route
$bypass->addRoute(method: 'GET', uri: '/v1/score/johndoe', status: 200, body: $body);

//Instantiates a TotalScoreService
$service = new TotalScoreService();

//Consumes the service using the Bypass URL
$response = $serivce
  ->setBaseUrl($bypassUrl) // set the URL to the Bypass URL
  ->getTotalScoreByUsername('johndoe'); //returns 35

//Pest PHP verify that response is 35
expect($response)->toBe(35);

//PHPUnit verify that response is 35
$this->assertSame($response, 35);

Quick Test Examples

Click below to see code snippets for Pest PHP and PHPUnit.

Pest PHP
use Ciareis\Bypass\Bypass;


it('properly returns the total score by username', function () {

  //Opens a new Bypass server
  $bypass = Bypass::open();

  //Json body
  $body = '{"games":[{"id":1, "name":"game 1","points":25},{"id":2, "name":"game 2","points":10}],"is_active":true}';

  //Defines a route
  $bypass->addRoute(method: 'GET', uri: '/v1/score/johndoe', status: 200, body: $body);

  //Instantiates and consumes the service using the Bypass URL
  $service = new TotalScoreService();
  $response = $service
    ->setBaseUrl($bypass->getBaseUrl())
    ->getTotalScoreByUsername('johndoe');

  //Verifies that response is 35
  expect($response)->toBe(35);
});

it('properly gets the logo', function () {

  //Opens a new Bypass server
  $bypass = Bypass::open();

  //Reads the file
  $filePath = 'docs/img/logo.png';
  $file = \file_get_contents($filePath);

  //Defines a route
  $bypass->addFileRoute(method: 'GET', uri: $filePath, status: 200, file: $file);

  //Instantiates and consumes the service using the Bypass URL
  $service = new LogoService();
  $response = $service->setBaseUrl($bypass->getBaseUrl())
    ->getLogo();

  // asserts
  expect($response)->toEqual($file);
});
PHPUnit
use Ciareis\Bypass\Bypass;


class BypassTest extends TestCase
{
  public function test_total_score_by_username(): void
  {
    //Opens a new Bypass server
    $bypass = Bypass::open();

    //Json body
    $body = '{"games":[{"id":1,"name":"game 1","points":25},{"id":2,"name":"game 2","points":10}],"is_active":true}';

    //Defines a route
    $bypass->addRoute(method: 'GET', uri: '/v1/score/johndoe', status: 200, body: $body);

    //Instantiates and consumes the service using the Bypass URL
    $service = new TotalScoreService();
    $response = $service
      ->setBaseUrl($bypass->getBaseUrl())
      ->getTotalScoreByUsername('johndoe');

    //Verifies that response is 35
    $this->assertSame(35, $response);
  }

  public function test_gets_logo(): void
  {
    //Opens a new Bypass server
    $bypass = Bypass::open();

    //Reads the file
    $filePath = 'docs/img/logo.png';
    $file = \file_get_contents($filePath);

    //Defines a route
    $bypass->addFileRoute(method: 'GET', uri: $filePath, status: 200, file: $file);

    //Instantiates and consumes the service using the Bypass URL
    $service = new LogoService();
    $response = $service->setBaseUrl($bypass->getBaseUrl())
      ->getLogo();

    $this->assertSame($response, $file);
  }
}

Test Examples

📚 See Bypass being used in complete tests with Pest PHP and PHPUnit for the GithubRepoService demo service.

Credits

And a special thanks to @DanSysAnalyst

Inspired

Code inspired by Bypass

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].