3

I've followed the unit testing tutorial and modified it to test a HTTP request to Micro MVC app, based on this post. I can successfully validate the output string, however I'm not sure how to assert the response status code or change the request path.

index.php

<?php

$app = new \Phalcon\Mvc\Micro();

#Default handler for 404
$app->notFound(function () use ($app) {
    $app->response->setStatusCode(404, "Not Found")->sendHeaders();
});

$app->post('/api/robots', function() use ($app) {
    //Parse JSON as an object
    $robot = $app->request->getJsonRawBody();
    //Build the response
    $app->response->setJsonContent($robot);
    return $app->response;
});

$app->get('/', function() {
    echo 'Hello';
});

$app->handle();

tests/UnitTest.php

class MvcMicroUnitTest extends \UnitTestCase {

    public function testNotFound() {
        $path = '/invalid';
        $mockRequest = $this->getMock("\\Phalcon\\Http\\Request");
        //TODO: Set an invalid URL $path in the mock
        $this->di->set('request', $mockRequest, true);
        include("../index.php");
        //TODO: Assert status is 404
        $this->expectOutputString('');
    }

    public function testPostRobot() {
        $rawJson = '{"name":"C-3PO","type":"droid","year":1977}';
        $path = '/api/robots';
        $mockRequest = $this->getMock("\\Phalcon\\Http\\Request", array(
            "getJsonRawBody"));
        $mockRequest->expects($this->any())
                ->method("getRawBody")
                ->will($this->returnValue($rawJson));
        //TODO: Set the $path in the mock
        $this->di->set('request', $mockRequest, true);
        include("../index.php");
        //TODO: Assert status is 200
        $this->expectOutputString($rawJson);
    }
}

1 Answer 1

1

Good news and bad news. Good: as far as you use the standard dispatching principle you will have a response, that would contain the information you need. Small trick – when status is success the header is set to false.

/**
 * @param $expected
 * @throws ExpectationFailedException
 * @return $this
 */
protected function assertResponseCode($expected)
{
    $actual = $this->di->getResponse()->getHeaders()->get('Status');

    if ($actual !== false && $expected !== 200 && !preg_match(sprintf('/^%s/', $expected), $actual)) {
        throw new ExpectationFailedException(sprintf('Failed asserting that response code is "%s".', $expected));
    }

    $this->assertTrue(true);
    return $this;
}

Bad: you are doing it the wrong way. This is area of functional / acceptance testing and there is a fabulous framework called Behat. You should do your own research, but essentially, while PHPUnit is great at testing more or less independent blocks of functionality it sucks at testing bigger things like full request execution. Later you will start experiencing issues with session errors, misconfigured environment, etc., all because each request is supposed to be executed in it's own separate space and you force it into doing the opposite. Behat on the other hand works in a very different way, where for each scenario (post robot, view non-existing page), it sends a fresh request to the server and checks the result. It is mostly used for final testing of everything working together by making assertions on the final result (response object / html / json).

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for your response! I'm definitely going to borrow your assertResponseCode function. Do you have any idea how to set the $path in the $mockRequest so it would be routed properly?
You can mock the request's getURI method, but it would be easier and probably better to directly change $_SERVER['REQUEST_URI'], that's what Phalcon uses internally.
Thanks, but it didn't work. What do I have to include for having ResponseHeaders available? Phalcon\Http\Response\Headers doesn't seem to have any constant. Also the $_SERVER['REQUEST_URI'] doesn't works for me either, everything goes to the index
My bad, it is working now, besides the request URI one need to also set $_GET["_url"] = $path;. Regarding the status code, only works for different than 200. Thanks to @twistedxtra for the hint.
Apologies, copied the ResponseCode from my old code, just use Status instead, updated the code.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.