InterNations / http-mock

Mock HTTP requests on the server side in your PHP unit tests
http://www.internations.org
MIT License
391 stars 62 forks source link

tearDownHttpMock fails when test runs in isolation #51

Open fcamp opened 5 years ago

fcamp commented 5 years ago

I have got a simple test for a gateway. Everything goes fine while the test is not ran in a separateProcess

    public function testSingle() {
        $this->http->mock
            ->when()
            ->then()
            ->callback(
                function (\Symfony\Component\HttpFoundation\Response $response) {
                    $response->setContent(file_get_contents(__DIR__ . '/../../xml/single.xml'))->setStatusCode(
                        200
                    );
                }
            )
            ->end();

        $this->http->setUp();
        //initialize gateway
        $response = $gateway->byName('my-name')->query();
        $rows = $response->getRows();
        self::assertCount(1, $rows);
    }

But If I add the runInSeparateProcess annotation, then tearDownHttpMock fails

   /**     
    *
    * @runInSeparateProcess
    * @preserveGlobalState disabled
    */
    public function testSingle() {
        //my code
    }

$server->getIncrementalErrorOutput() returns [Wed Apr 3 16:52:26 2019] Failed to listen on 127.0.0.1:33371 (reason: Address already in use)

As workaround I override the method into my test class

    protected function tearDownHttpMock()
    {
        if (!$this->http) {
            return;
        }

        //just skipping to make test work
        if($this->isInIsolation()){
            return;
        }

        $http = $this->http;
        $this->http = null;
        $http->each(
            function (HttpMockFacade $facade) {
                $this->assertSame(
                    '',
                    (string) $facade->server->getIncrementalErrorOutput(),
                    'HTTP mock server standard error output should be empty'
                );
            }
        );
    }

But I guess if there is another (better/proper) way to do this

lstrojny commented 5 years ago

Very interesting case. It seems like for some reason the test server is attempted to start more than once and the second attempt fails, that’s what the log message is telling me.

Can you add some logging to InterNations\Component\HttpMock\Server and dump the call stack into a file. Modifying start() to do something like this should work:

file_put_contents('/tmp/http-mock.log', (new \Exception)->getTraceAsString(), FILE_APPEND);

If you could attach the trace here, that would be lovely.

fcamp commented 5 years ago

I put the logging code here

public function start(callable $callback = null, array $env = [])
{
    parent::start($callback, $env);

    file_put_contents('/tmp/http-mock.log', (new \Exception)->getTraceAsString(), FILE_APPEND);

    $this->pollWait();
}

And executed the test twice by running phpunit --filter testSingle.

The first time I removed runInSeparateProcess annotation, the second I reset the annotation

This is the log

#no isolation
#0 /var/www-my-project/vendor/internations/http-mock/src/PHPUnit/HttpMockFacade.php(29): InterNations\Component\HttpMock\Server->start()
#1 /var/www-my-project/vendor/internations/http-mock/src/PHPUnit/HttpMockTrait.php(27): InterNations\Component\HttpMock\PHPUnit\HttpMockFacade->__construct(33371, '127.0.0.1', NULL)
#2 /var/www-my-project/tests/ControllerWithMockedHttpServer.php(21): MyApplication\Tests\MyGateway\ControllerWithMockedHttpServer::setUpHttpMockBeforeClass(33371, '127.0.0.1')
#3 /var/www-my-project/vendor/phpunit/phpunit/src/Framework/TestSuite.php(679): MyApplication\Tests\MyGateway\ControllerWithMockedHttpServer::setUpBeforeClass()
#4 /var/www-my-project/vendor/phpunit/phpunit/src/Framework/TestSuite.php(733): PHPUnit_Framework_TestSuite->run(Object(PHPUnit_Framework_TestResult))
#5 /var/www-my-project/vendor/phpunit/phpunit/src/TextUI/TestRunner.php(517): PHPUnit_Framework_TestSuite->run(Object(PHPUnit_Framework_TestResult))
#6 /var/www-my-project/vendor/phpunit/phpunit/src/TextUI/Command.php(186): PHPUnit_TextUI_TestRunner->doRun(Object(PHPUnit_Framework_TestSuite), Array, true)
#7 /var/www-my-project/vendor/phpunit/phpunit/src/TextUI/Command.php(116): PHPUnit_TextUI_Command->run(Array, true)
#8 /var/www-my-project/vendor/phpunit/phpunit/phpunit(52): PHPUnit_TextUI_Command::main()
#9 {main}
#
#@runInSeparateProcess
#0 /var/www-my-project/vendor/internations/http-mock/src/PHPUnit/HttpMockFacade.php(29): InterNations\Component\HttpMock\Server->start()
#1 /var/www-my-project/vendor/internations/http-mock/src/PHPUnit/HttpMockTrait.php(27): InterNations\Component\HttpMock\PHPUnit\HttpMockFacade->__construct(33371, '127.0.0.1', NULL)
#2 /var/www-my-project/tests/ControllerWithMockedHttpServer.php(21): MyApplication\Tests\MyGateway\ControllerWithMockedHttpServer::setUpHttpMockBeforeClass(33371, '127.0.0.1')
#3 /var/www-my-project/vendor/phpunit/phpunit/src/Framework/TestSuite.php(679): MyApplication\Tests\MyGateway\ControllerWithMockedHttpServer::setUpBeforeClass()
#4 /var/www-my-project/vendor/phpunit/phpunit/src/Framework/TestSuite.php(733): PHPUnit_Framework_TestSuite->run(Object(PHPUnit_Framework_TestResult))
#5 /var/www-my-project/vendor/phpunit/phpunit/src/TextUI/TestRunner.php(517): PHPUnit_Framework_TestSuite->run(Object(PHPUnit_Framework_TestResult))
#6 /var/www-my-project/vendor/phpunit/phpunit/src/TextUI/Command.php(186): PHPUnit_TextUI_TestRunner->doRun(Object(PHPUnit_Framework_TestSuite), Array, true)
#7 /var/www-my-project/vendor/phpunit/phpunit/src/TextUI/Command.php(116): PHPUnit_TextUI_Command->run(Array, true)
#8 /var/www-my-project/vendor/phpunit/phpunit/phpunit(52): PHPUnit_TextUI_Command::main()
#9 {main}#0 /var/www-my-project/vendor/internations/http-mock/src/PHPUnit/HttpMockFacade.php(29): InterNations\Component\HttpMock\Server->start()
#1 /var/www-my-project/vendor/internations/http-mock/src/PHPUnit/HttpMockTrait.php(27): InterNations\Component\HttpMock\PHPUnit\HttpMockFacade->__construct(33371, '127.0.0.1', NULL)
#2 /var/www-my-project/tests/ControllerWithMockedHttpServer.php(21): MyApplication\Tests\MyGateway\ControllerWithMockedHttpServer::setUpHttpMockBeforeClass(33371, '127.0.0.1')
#3 /var/www-my-project/vendor/phpunit/phpunit/src/Framework/TestCase.php(901): MyApplication\Tests\MyGateway\ControllerWithMockedHttpServer::setUpBeforeClass()
#4 /var/www-my-project/vendor/phpunit/phpunit/src/Framework/TestResult.php(686): PHPUnit_Framework_TestCase->runBare()
#5 /var/www-my-project/vendor/phpunit/phpunit/src/Framework/TestCase.php(868): PHPUnit_Framework_TestResult->run(Object(MyApplication\Tests\MyGateway\Modules\Gateway\GatewayFactoryTest))
#6 -(55): PHPUnit_Framework_TestCase->run(Object(PHPUnit_Framework_TestResult))
#7 -(103): __phpunit_run_isolated_test()
#8 {main}#0 /var/www-my-project/vendor/internations/http-mock/src/Server.php(104): InterNations\Component\HttpMock\Server->start()
#1 /var/www-my-project/vendor/internations/http-mock/src/PHPUnit/HttpMockFacade.php(80): InterNations\Component\HttpMock\Server->clean()
#2 /var/www-my-project/vendor/internations/http-mock/src/PHPUnit/HttpMockTrait.php(44): InterNations\Component\HttpMock\PHPUnit\HttpMockFacade->__clone()
#3 /var/www-my-project/tests/ControllerWithMockedHttpServer.php(36): MyApplication\Tests\MyGateway\ControllerWithMockedHttpServer->setUpHttpMock()
#4 /var/www-my-project/tests/Modules/Gateway/GatewayFactoryTest.php(29): MyApplication\Tests\MyGateway\ControllerWithMockedHttpServer->setUp()
#5 /var/www-my-project/vendor/phpunit/phpunit/src/Framework/TestCase.php(909): MyApplication\Tests\MyGateway\Modules\Gateway\GatewayFactoryTest->setUp()
#6 /var/www-my-project/vendor/phpunit/phpunit/src/Framework/TestResult.php(686): PHPUnit_Framework_TestCase->runBare()
#7 /var/www-my-project/vendor/phpunit/phpunit/src/Framework/TestCase.php(868): PHPUnit_Framework_TestResult->run(Object(MyApplication\Tests\MyGateway\Modules\Gateway\GatewayFactoryTest))
#8 -(55): PHPUnit_Framework_TestCase->run(Object(PHPUnit_Framework_TestResult))
#9 -(103): __phpunit_run_isolated_test()
#10 {main}

I hope it helps :smile: