Mock Slim endpoint POST requests with PHPUnit

I want to test the endpoints of my Slim application with PHPUnit. I’m struggling to mock POST requests (the request body is always empty).

  • I’ve tried the approach as described here: LINK_OMITTED. (adding the environment variable slim-input)
  • I’ve tried writing to php://input directly, but I’ve found out php://input is read only (the hard way)

The emulation of the environment works correctly as for example the REQUEST_URI is always as expected. I’ve found out that the body of the request is read out in Slim\Http\RequestBody from php://input.

my test code so far:

//inherits from Slim/App
$this->app = new SyncApiApp(); 

// write json to //temp, does not work
$tmp_handle = fopen('php://temp', 'w+');
fwrite($tmp_handle, $json);
rewind($tmp_handle);
fclose($tmp_handle);

//override environment
$this->app->container["environment"] =
    Environment::mock(
        [
            'REQUEST_METHOD' => 'POST',
            'REQUEST_URI' => '/1.0/' . $relativeLink,
            'slim.input' => $json,
            'SERVER_NAME' => 'localhost',
            'CONTENT_TYPE' => 'application/json;charset=utf8'
        ]
    );

 //run the application
 $response = $this->app->run();
 //result: the correct endpoint is reached, but $request->getBody() is empty

My test code on github (be aware that I’ve simplified the code in the example): LINK_OMITTED

Notes:

  • I want to avoid calling the controller methods directly, so I can test everything, including endpoints.
  • I want to avoid guzzle because it sends an actual request. I do not want to have a server running while testing the application.
  • I’ve posted the exact same question to stackoverflow 2 days ago: http://stackoverflow.com/questions/40867377/mock-slim-endpoint-post-requests-with-phpunit. I hope you’re not mad about this, and I promise to keep both sites up to date :slight_smile: You’ll find there all the omitted links too
  • I’d be very open for suggestions on how to improve the architecture of the application if something caches your attention

I’m quite inexperienced when it comes to PHPUnit, but have you read through Testing Slim Framework Actions?

I’m aware of this blog post, but unfortunately it uses the query parameters to submit the “infomation” rather than the body of a POST request.

PHPUnit is for testing purposes, its a framework which basically executes one test method at a time, and evaluates some assert statements. It therefore allows me to test some methods from my Slim application.

I’ve started using PHPUnit a bit, so I know what it is, but I’m just getting started. Perhaps a ping to @geggleto, @silentworks, @JoeBengalen r @akrabat as I bet one of them can help steer you in the right direction.

I’ve read now large parts of the source code (which is not that large to be honest), and I personally see no way this would work with the current set up. I’ve implemented the functionality with a new environment variable and will try my luck with a pull request today.

I’ve create a pull request for a patch which would enable the feature: https://github.com/slimphp/Slim/pull/2086
As there are some other open, unanswered pull requests it is probably gonna take some time till it gets accepted/rejected. Thanks for your help :slight_smile:

I’m so sorry for being late to the party…

I had written something up for mocking Slim Requests… http://glenneggleton.com/page/slim-unit-testing
Akrabat also has a page on it here… https://akrabat.com/testing-slim-framework-actions/

Thanks! It needs some more time to setup, but nonetheless works better than my solution, as one does not need to introduce a new “magic” key into the environment. My solution:

//setup environment vals to create request
$env = Environment::mock();
$uri = Uri::createFromString('/1.0/' . $relativeLink);
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new RequestBody();
$uploadedFiles = UploadedFile::createFromEnvironment($env);
$request = new Request('GET', $uri, $headers, $cookies, $serverParams, $body, $uploadedFiles);

//write request data
$request->write(json_encode([ 'key' => 'val' ]));
$request->getBody()->rewind();
//set method & content type
$request = $request->withHeader('Content-Type', 'application/json');
$request = $request->withMethod('POST');

//execute request
$app = new App();
$resOut = $app($request, new Response());
$resOut->getBody()->rewind();

$this->assertEquals('full response text', $resOut->getBody()->getContents());
1 Like

My current solution is to just grab the Request object from the container, modify it then just pass it into whatever controller I am trying to test. :thumbsup:

For the record, I’ve followed http://lzakrzewski.com/2016/02/integration-testing-with-slim/ which is working really well for me.

1 Like

It should be noted that this will NOT run middleware during unit testing, I had to:
$app->process($request, $response)
in order for jwt middleware to work, for example.