Coder Social home page Coder Social logo

mateusjatenee / bypass Goto Github PK

View Code? Open in Web Editor NEW

This project forked from ciareis/bypass

0.0 2.0 0.0 724 KB

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

License: MIT License

PHP 100.00%

bypass's Introduction

Bypass Logo

Bypass for PHP

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

US flag in base64 BR flag in base64

PHP Composer 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

Writing Tests

Content

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

1. Open a Bypass Service

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

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

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

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

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

//Your test assertions here...

The method addRoute() accepts the following parameters:

Parameter Type Description
HTTP Method int $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 $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

//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 int $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 $body Binary file to be served by Bypass
Times int $times How many times the route should be called (default: 1)

4. Asserting Route Calling

You might 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 = '{"name": "John", "total": 1250}';

//Defines a route which must be called two times
$bypass->addRoute(method: 'get', uri: '/v1/demo', 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())
  ->getTotal();

$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
}
//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
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
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

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.