Mock HTTP requests on the server side in your PHP unit tests

Related tags

Testing http-mock
Overview

HTTP Mock for PHP

Gitter Build Status Dependency Status Average time to resolve an issue Percentage of issues still open

Mock HTTP requests on the server side in your PHP unit tests.

HTTP Mock for PHP mocks the server side of an HTTP request to allow integration testing with the HTTP side. It uses PHP’s builtin web server to start a second process that handles the mocking. The server allows registering request matcher and responses from the client side.

BIG FAT WARNING: software like this is inherently insecure. Only use in trusted, controlled environments.

Usage

Read the docs

Comments
  • No post data in request

    No post data in request

    Library doesn't parse POST data in request body

    I send request throw php curl and it accepts fine in nginx, nodejs but

    $this->http->requests->latest()->getPostFields()
    

    is empty.

    opened by AlexMarlo 14
  • Weird behavior with PHP 7.4, symfony/process and stderr output

    Weird behavior with PHP 7.4, symfony/process and stderr output

    Hello!

    After I updated my project to use PHP 7.4, now when I try to run my integration tests I always get a very weird output from the stderr pipe when running HttpMockTrait::tearDownHttpMock();:

    HTTP mock server standard error output should be empty
    Failed asserting that two strings are identical.
    --- Expected
    +++ Actual
    @@ @@
    -''
    +'[Fri Feb 21 18:48:56 2020] 127.0.0.1:59798 Accepted
    +[Fri Feb 21 18:48:56 2020] 127.0.0.1:59798 Closing
    +[Fri Feb 21 18:48:56 2020] 127.0.0.1:59800 Accepted
    +[Fri Feb 21 18:48:57 2020] 127.0.0.1:59800 Closing
    +[Fri Feb 21 18:48:57 2020] 127.0.0.1:59802 Accepted
    +[Fri Feb 21 18:48:57 2020] 127.0.0.1:59802 Closing
    +[Fri Feb 21 18:48:57 2020] 127.0.0.1:59804 Accepted
    +[Fri Feb 21 18:48:57 2020] 127.0.0.1:59804 Closing
    +[Fri Feb 21 18:48:57 2020] 127.0.0.1:59806 Accepted
    +[Fri Feb 21 18:48:57 2020] 127.0.0.1:59806 Closing
    +[Fri Feb 21 18:48:57 2020] 127.0.0.1:59808 Accepted
    +[Fri Feb 21 18:48:57 2020] 127.0.0.1:59808 Closing
    +[Fri Feb 21 18:48:57 2020] 127.0.0.1:59810 Accepted
    +[Fri Feb 21 18:48:57 2020] 127.0.0.1:59810 Closing
    +[Fri Feb 21 18:48:57 2020] 127.0.0.1:59812 Accepted
    +[Fri Feb 21 18:48:57 2020] 127.0.0.1:59812 Closing
    +'
    

    All my tests are failing because of the same error. If I stop calling the $this->tearDownHttpMock();, then the tests starts passing.

    Someone else is experiencing this too? It's happening only after I updated the PHP version. This is some kind of new behavior of Php? Shouldn't this output be directed to the stdout pipe instead of the stderr? I mean, these are not errors, they're just logs in fact.

    I'm not even sure if the issue is with internations/http-mock or symfony/process, so, I'm sorry if this issue isn't in the correct place.

    opened by gabfr 12
  • Check that server didn't receive any or particular request

    Check that server didn't receive any or particular request

    I have functionality when i need to know that part of the code which call remote server wasn't called. For now i don't see such functionality in library. Any ideas?

    opened by AlexMarlo 8
  • Real mocks instead of stubs

    Real mocks instead of stubs

    I think that now HTTP mocks are more simple stubs, they aren't mocks in classical meaning (because they don't set any assertions based on prepared HTTP queries).

    For example, if I write a test with a classic mock object in PHPUnit:

        public function testMock()
        {
            $mock = $this->getMock(\ArrayObject::class);
            $mock->expects($this->once())->method('count')->willReturn(5);
    
            assertTrue(true);
        }
    

    I will get it failed:

    There was 1 failure:
    
    1) ExampleTest::testMock
    Expectation failed for method name is equal to <string:count> when invoked 1 time(s).
    Method was expected to be called 1 times, actually called 0 times.
    

    But with HTTP mocks behaviour isn't the same. expects() works only to restrict HTTP calls inside a web server, but not for tests.

    What do you think about automatic addition of assertions for HTTP mocks, like it's done for class/interface mocks?

    opened by alexeyshockov 6
  • register different successive responses for the same endpoint

    register different successive responses for the same endpoint

    Hi,

    first of all, thanks for this software.

    Then, here is a feature request: I'm trying to test a "retry" feature in my http client. So I would like to be able to set up http-mock so that the 1st query it receives returns a response with status code 500, and so that the 2nd query it receives returns a response with status code 200. I've looked at the doc, made some experiments but couldn't find a way to do i (in particular I tried to redefine the behavior of the mock in a ->then()->callback(...) but that didn't seem to work).

    To put it in a nutshell:

    • Is it already possible to do this kind of setup? If yes, would it be possible to add some doc about it?
    • If it's not possible, does it seem like a feature you might want to consider?
    opened by gturri 5
  • Provide an absolute path to the router for the PHP CLI server to fix

    Provide an absolute path to the router for the PHP CLI server to fix "No such file or directory" error

    In PHP source commit: https://github.com/php/php-src/commit/816758eda2bcdd69ba505fb6bbb79124a7bf2254 made to fix #75287, there is a change to how the router argument is passed in. Previously, the CLI accepted relative paths (to the current working directory) for the router argument. After this change, it either uses an absolute path, or concatenates the server docroot and the router if an absolute path is not provided. This causes the error seen in #39.

    While normally this would be fixed by just changing the router argument to index.php, it breaks compatibility with PHP version 7.1.11 and below as those versions expect an absolute path. Thus, this fix involves getting the absolute path to the router file and passing that in instead.

    I have tested this on both 7.1.11 and 7.1.12 and it works.

    opened by EricTendian 5
  • Checking request query string?

    Checking request query string?

    Is there a way to check the query string of a request (particularly for GET requests)? I want to make sure a transformation in my request wrapper actually occurs when I make the request.

    If this isn't yet possible, here's the API I would expect:

    $this->http->mock
        ->when()
            ->methodIs("GET")
            ->pathIs("/my/test/path")
            ->queryIs("param1=test1&param2=test2")
        ->then()->body("{}")->statusCode(200)
        ->end();
    

    or

    $this->http->mock
        ->when()
            ->methodIs("GET")
            ->pathIs("/my/test/path")
            ->queryIs(array("param1" => "test1", "param2" => "test2"))
        ->then()->body("{}")->statusCode(200)
        ->end();
    

    PS: Thank you for making this library. It's nice to be able to mock HTTP requests in my test suite.

    opened by michaelherold 5
  • PHPUnit WebTestCase failing when 2 tests are using the same port.

    PHPUnit WebTestCase failing when 2 tests are using the same port.

    Using PHP 5.6.18 with PHPUnit 5.7.5, the following error is produced: UnexpectedValueException: Expected status code 200 from "/_request/2", got 404

    The call is from the first test with a loop which is calling $this->http->requests->at($i);.

    The codes in the first class is:

    /**
         * @beforeClass
         * @SuppressWarnings(PHPMD.StaticAccess)
         */
        public static function init()
        {
            static::setUpHttpMockBeforeClass('8880', 'localhost');
        }
    
        /**
         * @afterClass
         */
        public static function shutdown()
        {
            static::tearDownHttpMockAfterClass();
        }
    
        public function testMethod()
        {
            // do stuffs
               $this->http->requests->at($i);
            //do other stuffs
        }
    

    And the second class is

        public static function setUpBeforeClass()
        {
            static::setUpHttpMockBeforeClass('8880', 'localhost');
        }
    
        public static function tearDownAfterClass()
        {
            static::tearDownHttpMockAfterClass();
        }
    
        // other stuff
    

    Both class extends from WebTestCase and use the HttpMockTrait

    When the port is different in the second class or the second test is skipped, the test runs successfully.

    opened by Locustv2 4
  • Update http-mock to work with jeremeamia/SuperClosure v2

    Update http-mock to work with jeremeamia/SuperClosure v2

    dependent lib jeremeamia/SuperClosure was updated to v2, and your code stopped to work(

    PHP Fatal error: Class 'Jeremeamia\SuperClosure\SerializableClosure' not found in /work/www/tsw/vendor/internations/http-mock/src/InterNations/Component/HttpMock/Matcher/AbstractMatcher.php on line 32

    easy-pick 
    opened by fizzka 4
  • PHPUnit failing

    PHPUnit failing

    I've done

    git clone [email protected]:InterNations/http-mock.git
    cd http-mock
    composer install
    phpunit
    

    And am getting tons of failures, all along the lines of:

    1. InterNations\Component\HttpMock\Tests\PHPUnit\HttpMockPHPUnitIntegrationTest::testLimitDurationOfAResponse Guzzle\Http\Exception\CurlException: [curl] 52: Empty reply from server [url] http://localhost:28080/_all

    ~/dev/http-mock/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php:420 ~/dev/http-mock/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php:354 ~/dev/http-mock/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php:286 ~/dev/http-mock/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php:247 ~/dev/http-mock/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php:140 ~/dev/http-mock/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMultiProxy.php:106 ~/dev/http-mock/vendor/guzzle/guzzle/src/Guzzle/Http/Client.php:385 ~/dev/http-mock/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php:258 ~/dev/http-mock/src/InterNations/Component/HttpMock/Server.php:97 ~/dev/http-> mock/src/InterNations/Component/HttpMock/PHPUnit/HttpMockFacade.php:76 ~/dev/http-mock/src/InterNations/Component/HttpMock/PHPUnit/HttpMockTrait.php:26 ~/dev/http-mock/tests/InterNations/Component/HttpMock/Tests/PHPUnit/HttpMockPHPUnitIntegrationTest.php:24

    I'm running PHP 5.4.11 and have curl extension installed. Do you have any idea what the issue might be?

    Thanks!

    opened by maxenglander 4
  • Make it possible to have different responses for successive calls

    Make it possible to have different responses for successive calls

    This implements the feature request #61

    This features required the addition of an attribute on the Expectations because we need a new behavior on the App side since we have to increment the "run" counter even if the "limiter" doesn't match. However, this addition is implemented in a completely backward compatible way.

    opened by gturri 3
  • php8 compatibility

    php8 compatibility

    According to dc87f315611e5bb83727a1947bf94e707aace0d1 http-mock is compatible with PHP8. It would be really cool to release a package which updates this constraint in order to be able to use http-mock on a CI running on this version of PHP8. Is it something you could consider doing?

    opened by gturri 2
  • "Uncaught Error: Function name must be a string" when matching on a callback

    Hi,

    I'm trying to follow the 2nd snippet of the doc here https://github.com/InterNations/http-mock/blob/main/doc/stubbing.md but I get an error. I'm not sure if I'm doing something wrong or if there is an issue and I would be thrilled if you can give me pointer to fix it. Here is my code:

    <?php
    declare(strict_types=1);
    
    use InterNations\Component\HttpMock\PHPUnit\HttpMockTrait;
    use PHPUnit\Framework\TestCase;
    use Symfony\Component\HttpFoundation\Request;
    
    final class CalDAVUTest extends TestCase {
        use HttpMockTrait;
        public static function setUpBeforeClass() : void {
            static::setUpHttpMockBeforeClass('8082', 'localhost');
        }
        public static function tearDownAfterClass() : void {
            static::tearDownHttpMockAfterClass();
        }
        public function setUp() : void {
            $this->setUpHttpMock();
        }
        public function tearDown() : void {
            $this->tearDownHttpMock();
        }
    
        public function test_doc(){
            $this->http->mock
                ->when()
                    ->callback(
                        static function (Request $request) {
                            return $request->getMethod() === 'GET' && $request->getPathInfo() === '/resource';
                        }
                    )
                ->then()
                    ->callback(
                        static function (Response $response) {
                            $response->setBody('response');
                        }
                    )
                ->end();
            $this->http->setUp();
    
    
            $curl = curl_init("http://localhost:8082/resource");
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
            curl_exec($curl);
        }
    }
    
    

    and here is the error I have:

    1) CalDAVUTest::test_doc
    HTTP mock server standard error output should be empty
    Failed asserting that two strings are identical.
    --- Expected
    +++ Actual
    @@ @@
    -''
    +'[Tue Dec 21 22:59:15 2021] PHP Fatal error:  Uncaught Error: Function name must be a string in /documents/zwp/slack-agenda-app/vendor/jeremeamia/superclosure/src/SerializableClosure.php(210) : eval()'d code:2
    +Stack trace:
    +#0 [internal function]: InterNations\Component\HttpMock\Matcher\AbstractMatcher::{closure}()
    +#1 /documents/zwp/slack-agenda-app/vendor/jeremeamia/superclosure/src/SerializableClosure.php(75): call_user_func_array()
    +#2 /documents/zwp/slack-agenda-app/vendor/internations/http-mock/src/app.php(130): SuperClosure\SerializableClosure->__invoke()
    +#3 [internal function]: InterNations\Component\HttpMock\{closure}()
    +#4 /documents/zwp/slack-agenda-app/vendor/silex/silex/src/Silex/ExceptionListenerWrapper.php(53): call_user_func()
    +#5 /documents/zwp/slack-agenda-app/vendor/symfony/event-dispatcher/EventDispatcher.php(264): Silex\ExceptionListenerWrapper->__invoke()
    +#6 /documents/zwp/slack-agenda-app/vendor/symfony/event-dispatcher/EventDispatcher.php(239): Symfony\Component\EventDispatcher\EventDispatcher->doDispatch()
    +#7 /documents/zwp/slack-agen in /documents/zwp/slack-agenda-app/vendor/jeremeamia/superclosure/src/SerializableClosure.php(210) : eval()'d code on line 2'
    
    /documents/zwp/slack-agenda-app/vendor/internations/http-mock/src/PHPUnit/HttpMockTrait.php:73
    /documents/zwp/slack-agenda-app/vendor/internations/http-mock/src/PHPUnit/HttpMockFacade.php:85
    /documents/zwp/slack-agenda-app/vendor/internations/http-mock/src/PHPUnit/HttpMockTrait.php:75
    /documents/zwp/slack-agenda-app/tests/CalDAVUTest.php:20
    

    Here is the relevant part of my composer.json:

        "require-dev": {
            "phpunit/phpunit": "^9.5",
            "internations/http-mock": "^0.14.0"
        }
    

    (and in my composer.lock I see that I'm using jeremeamia/superclosure version 2.4.0)

    Does this error rings a bell?

    opened by gturri 1
  • Fix requests with files on php74 branch

    Fix requests with files on php74 branch

    Related to https://github.com/InterNations/http-mock/pull/65#issuecomment-919783476 and based on the suggestions given in https://github.com/InterNations/http-mock/pull/65#issuecomment-928958009.

    opened by DavidePastore 0
Owner
InterNations GmbH
InterNations GmbH
SimpleTest is a framework for unit testing, web site testing and mock objects for PHP

SimpleTest SimpleTest is a framework for unit testing, web site testing and mock objects for PHP. Installation Downloads All downloads are stored on G

SimpleTest 147 Jun 20, 2022
This plugin adds basic HTTP requests functionality to Pest tests, using minicli/curly

Curly Pest Plugin This plugin adds basic HTTP requests functionality to Pest tests, using minicli/curly. Installation composer require minicli/pest-pl

minicli 16 Mar 24, 2022
Very simple mock HTTP Server for testing Restful API, running via Docker.

httpdock Very simple mock HTTP Server for testing Restful API, running via Docker. Start Server Starting this server via command: docker run -ti -d -p

Vo Duy Tuan 4 Dec 24, 2021
PHP Test Generator - A CLI tool which generates unit tests

This project make usages of PHPStan and PHPParser to generate test cases for a given PHP File.

Alexander Schranz 7 Dec 3, 2022
To run time/IO related unit tests (e.g., sleep function calls, database queries, API calls, etc) faster using Swoole.

To run time/IO related unit tests (e.g., sleep function calls, database queries, API calls, etc) faster using Swoole.

Demin Yin 11 Sep 9, 2022
Mock built-in PHP functions (e.g. time(), exec() or rand())

PHP-Mock: mocking built-in PHP functions PHP-Mock is a testing library which mocks non deterministic built-in PHP functions like time() or rand(). Thi

null 331 Jan 3, 2023
A simple way to mock a client

Mocked Client A simple way to mock a client Install Via Composer $ composer require doppiogancio/mocked-client guzzlehttp/guzzle php-http/discovery No

Fabrizio Gargiulo 17 Oct 5, 2022
Mock implementation of the Translation package, for testing with PHPUnit

PoP Translation - Mock Mock implementation of the Translation package, for testing with PHPUnit Install Via Composer composer require getpop/translati

PoP 1 Jan 13, 2022
Mockery - Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library

Mockery Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its c

Mockery 10.3k Jan 1, 2023
Extension to use built-in PHP server on Behat tests

Extension to use built-in PHP server on Behat tests Instalation composer require libresign/behat-builtin-extension Configuration Add the extension to

LibreSign 2 Feb 21, 2022
The modern, simple and intuitive PHP unit testing framework.

atoum PHP version atoum version 5.3 -> 5.6 1.x -> 3.x 7.2 -> 8.x 4.x (current) A simple, modern and intuitive unit testing framework for PHP! Just lik

atoum 1.4k Nov 29, 2022
The PHP Unit Testing framework.

PHPUnit PHPUnit is a programmer-oriented testing framework for PHP. It is an instance of the xUnit architecture for unit testing frameworks. Installat

Sebastian Bergmann 18.8k Jan 4, 2023
PHP unit testing framework with built in mocks and stubs. Runs in the browser, or via the command line.

Enhance PHP A unit testing framework with mocks and stubs. Built for PHP, in PHP! Quick Start: Just add EnhanceTestFramework.php and you are ready to

Enhance PHP 67 Sep 12, 2022
Unit testing tips by examples in PHP

Unit testing tips by examples in PHP Introduction In these times, the benefits of writing unit tests are huge. I think that most of the recently start

Kamil Ruczyński 894 Jan 4, 2023
Real-world Project to learning about Unit Testing/TDD with Laravel for everybody

KivaNote - a Laravel TDD Sample Project Let me introduce you to KivaNote, a simple real-world application using Laravel to show you how the TDD & Unit

(Seth) Phat Tran 10 Dec 31, 2022
Package for unit testing Laravel form request classes

Package for unit testing Laravel form request classes. Why Colin DeCarlo gave a talk on Laracon online 21 about unit testing Laravel form requests cla

null 18 Dec 11, 2022
Learn unit testing with PHPUnit.

PHPUnit Exercise Running PHPUnit ./vendor/bin/phpunit # with filter which tests to run ./vendor/bin/phpunit --filter <pattern> Running Pint ./vendor/

Nopal 2 Aug 23, 2022
Enforce consistent styling for your Pest PHP tests

A set of PHP CS rules for formatting Pest PHP tests.

Worksome 2 Mar 15, 2022