Giter VIP home page Giter VIP logo

asynit's Introduction

asynit

Asynchronous HTTP Request Testing Library for API or more...

Install

composer require --dev jolicode/asynit

Usage

Asynit

Basic usage

Asynit will read PHP's classes and try to mimic the API of PHPUnit, so you need to a create a test class in some directory, which will extends the TestCase class of Asynit:

use Asynit\TestCase;

class ApiTest extends TestCase
{
}

Then you can add some tests that will use the API of the TestCase class:

use Asynit\TestCase;
use Psr\Http\Message\ResponseInterface;

class ApiTest extends TestCase
{
    public function testGet()
    {
        $this->get('http://my-site-web')->shouldResolve(function (ResponseInterface $response) {
            if ($response->getStatusCode() !)= 200) {
                throw \Exception('bad status code');
            }
        });
    }
}

Here we tell the test to do a GET request on http://my-site-web then we pass it a callback that will be called when the response will be available. Having this API allows to launch multiple requests in parallels without blocking.

You can also note that there is no assert, this library doesn't provide that, instead it uses exception to detect failure. A failed test is a test that throws an exception. If you want to use assertion there is numerous library that can handle this use case.

For running this test you will only need to use the PHP file provided by this project:

$ php vendor/bin/asynit tests-directory/

Overriding HTTP Client

Like PHPUnit you can add a special method named setUp to your test case. This special method will be run before each test and can also be used to override the http client.

use Asynit\TestCase;
use Http\Client\HttpAsyncClient;

class ApiTest extends TestCase
{
    public function setUp(HttpAsyncClient $asyncClient)
    {
        return $asyncClient;
    }
}

The underlying client is a React one respecting the HTTPlug Async interface. So you can use any library that is compatible with this standard. As an example you can add the BaseUri plugin to prefix all your requests with a specific url:

use Asynit\TestCase;
use Http\Client\Common\Plugin\BaseUriPlugin;
use Http\Client\Common\PluginClient;
use Http\Client\HttpAsyncClient;
use Http\Message\UriFactory\GuzzleUriFactory;

class ApiTest extends TestCase
{
    public function setUp(HttpAsyncClient $asyncClient)
    {
        return new PluginClient($asyncClient, [
            new BaseUriPlugin((new GuzzleUriFactory())->createUri('http://my-site-web')),
        ]);
    }
    
    public function testGetHome()
    {
        $this->get('/')->shouldResolve(function (ResponseInterface $response) {
            if ($response->getStatusCode() !)= 200) {
                throw \Exception('bad status code');
            }
        });
    }
    
    public function testPostContact()
    {
        $this->post('/contact')->shouldResolve(function (ResponseInterface $response) {
            if ($response->getStatusCode() !)= 200) {
                throw \Exception('bad status code');
            }
        });
    }
}

Dependency between tests

Sometime a test may need a value from the result of another test, like an authentication token that need to be available for some requests (or a cookie defining the session).

Asynit provides a Depend annotation which allows you to specify that a test is dependent from another one.

So if you have 3 tests, A, B and C and you say that C depend on A; A and B will be run in parallel and once A is completed and successful, C will be run with the result from A, let's see an example:

namespace Application\ApiTest;

use Asynit\Annotation\Depend;
use Asynit\TestCase;
use Http\Client\Common\Plugin\BaseUriPlugin;
use Http\Client\Common\PluginClient;
use Http\Client\HttpAsyncClient;
use Http\Message\UriFactory\GuzzleUriFactory;

class SecurityTest extends TestCase
{
    public function setUp(HttpAsyncClient $asyncClient)
    {
        return new PluginClient($asyncClient, [
            new BaseUriPlugin((new GuzzleUriFactory())->createUri('http://my-site-web')),
        ]);
    }
    
    public function &testLogin()
    {
        $token = null;
    
        $this->post('/', [], '{ "username": "user", "password": "pass" }')->shouldResolve(function (ResponseInterface $response) use(&$token) {
            if ($response->getStatusCode() !)= 200) {
                throw \Exception('bad status code');
            }
            
            $token = $response->getBody()->getContents();
        });
        
        return $token;
    }
    
    /**
     * @Depend("testLogin")
     */
    public function testAuthenticatedRequest($token)
    {
        $this->get('/api', ['X-Auth-Token' => $token])->shouldResolve(function (ResponseInterface $response) {
            if ($response->getStatusCode() !)= 200) {
                throw \Exception('bad status code');
            }
        });
    }
}

Here testAuthentifactedRequest will only be run after testLogin has been completed. You can also use dependency between different test case. The previous test case is under the Application\ApiTest namespace and thus we can write another test case like this:

class PostTest
{
    /**
     * @Depend("Application\ApiTest\SecurityTest::testLogin")
     */
    public function testGet($token)
    {
        $this->get('/posts', ['X-Auth-Token' => $token])->shouldResolve(function (ResponseInterface $response) {
            if ($response->getStatusCode() !)= 200) {
                throw \Exception('bad status code');
            }
        });
    }
}

Smoker

Smoker use the Asynit API to provide a simple way to test many urls when there is no need to have a complex logic of testing.

You just have to defined a yaml file like the following:

"https://jolicode.com/":
    status: 200

"https://jolicode.com/equipe":
    status: 200

"https://jolicode.com/nos-valeurs":
    status: 200

And then run the php smoker cli on it:

php bin/smoker test.yml

asynit's People

Contributors

damienalexandre avatar joelwurtz avatar tlenclos avatar

Watchers

 avatar  avatar

Forkers

camilogarzon

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.