Controller unit test in slim3
Asked Answered
F

1

10

At the outset, I would like to say - I'm new in unit testing in PHP (phpunit). In my new project (slim3 framework) I would like to test my controllers for example LoginController.

My idea is (in unit test method)

  • Create instance of LoginController
  • Mock some services in controller (DI)
  • Execute method which is response for request (in my controllers method __invoke)

My problem is about parameters for __invoke method. In Slim3 callable method for request has two first params:

RequestInterface $request and ResponseInterface $response

How can I create this parameters in my unit test class? I was searching for some examples for this issue but without success.

Any suggestions?

I've found some code in Slim3 tests to mock request:

protected function requestFactory()
{
    $uri = Uri::createFromString('https://example.com:443/foo/bar?abc=123');
    $headers = new Headers();
    $cookies = array(
        'user' => 'john',
        'id' => '123',
    );
    $env = Slim\Http\Environment::mock();
    $serverParams = $env->all();
    $body = new Body(fopen('php://temp', 'r+'));
    $request = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);

    return $request;
}

But I'm not sure that is good way.

Thanks for any help

Freed answered 19/3, 2016 at 22:17 Comment(0)
A
21

I wrote up one solution here: https://akrabat.com/testing-slim-framework-actions/

I use Environment::mock() to create a $request and then I can run the action. Making each route callable a class where all dependencies are injected into the constructor makes this all much easier too.

Essentially, a test looks like this:

class EchoActionTest extends \PHPUnit_Framework_TestCase
{
    public function testGetRequestReturnsEcho()
    {
        // instantiate action
        $action = new \App\Action\EchoAction();

        // We need a request and response object to invoke the action
        $environment = \Slim\Http\Environment::mock([
            'REQUEST_METHOD' => 'GET',
            'REQUEST_URI' => '/echo',
            'QUERY_STRING'=>'foo=bar']
        );
        $request = \Slim\Http\Request::createFromEnvironment($environment);
        $response = new \Slim\Http\Response();

        // run the controller action and test it
        $response = $action($request, $response, []);
        $this->assertSame((string)$response->getBody(), '{"foo":"bar"}');
    }
}
Arose answered 20/3, 2016 at 9:16 Comment(4)
This worked great for me! Thanks @rob (The solution write up on your website was helpful too)Landfall
Thanks for this code, @rob-allen! How would you suggest we do something similar if our routes are defined via anonymous functions? (For example: $app->get("/test/{id}", function($request, $response, $args) { ... });)Payday
I figured it out. For those who are curious, you'll need to make your anonymous function into a named function (e.g. echo_action()). Then, instead of $action = new \App\Action\EchoAction();, use $action = "echo_action";Payday
Thanks for the notes @ringo. Testing anonymous functions is hardArose

© 2022 - 2024 — McMap. All rights reserved.