We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Controller unit testing

Hello guys,

I'm having a hard time trying to test controllers and their actions. I don't understand, how should I properly test controller actions, since their execution usually doesn't return anything and everything is handled by the application. This is what I have so far:

Controller

class UserController extends Controller
{

    public function signInAction()
    {
        if ($this->auth->isAuthenticated()) {
            return $this->response->redirect();
        }

        $form = new UserSignInForm(new Users);
        $messages = array();

        if ($this->request->isPost()) {
            if ($form->isValid($_POST, $form->getEntity())) {
                try {
                    $this->auth->login($form->getValue('email'), $form->getValue('password'));
                    return $this->response->redirect();
                } catch (AuthenticationException $e) {
                    $messages[] = $e->getMessage();
                }
            } else {
                $messages = $form->getMessages();
            }
        }

        $this->view->form = $form;
        $this->view->messages = $messages;
    }

}

UnitTestCase

use Phalcon\DI;

abstract class UnitTestCase extends \PHPUnit_Framework_TestCase
{
    /**
     * @var Phalcon\DI
     */
    protected $di;

    /**
     * @var bool
     */
    private $_loaded = false;

    protected function setUp()
    {
        $this->checkExtension('phalcon');

        $this->di = DI::getDefault();
        $this->_loaded = true;
    }

    public function checkExtension($extension)
    {
        if (!extension_loaded($extension)) {
            $this->markTestSkipped("Warning: {$extension} extension is not loaded");
        }
    }

    /**
     * Check if the test case is setup properly
     * @throws \PHPUnit_Framework_IncompleteTestError;
     */
    public function __destruct() {
        if(!$this->_loaded) {
            throw new \PHPUnit_Framework_IncompleteTestError('Please run parent::setUp().');
        }
    }

}

UserControllerTest

class UserControllerTest extends \UnitTestCase
{

    public function testGetSignUpAction()
    {
        $controller = new UserController;
        $controller->signInAction();
    }

}

The signInActions returns no response nor any content, so I'm unable to make any assertions to check if the actions runs and renders the template properly.

What is the best practice here? Should my controllers manually render the desired templates or should I use $application->handle()->getContent(); with url to test the controller action reliably? Or just make requests via curl?

Thank you for your help!



40.8k
Accepted
answer

I think that you should do rather functional testing for application
More you can find here https://codeception.com/

Yeah, you're right, I should be implementing functional tests for the application and unit tests for models and so on.

Thanks for pointing the right direction :)

I'm digging this up to point out to whomever reading that I don't believe you were pointed to the right direction. I've seen a lot of controller unit tests in different platforms, and the people who wrote them weren't wrong. You should be able to unit test your controller actions.

Controller actions should be tested on whatever it's their responsability. They are just methods, if the method sets up a redirect, then the redirect should be tested. If it renders a particular view in a particular situation, then that should be tested.

I have just been trying to work this out this afternoon.

All you need to do is set your output fucntion and response function back into your DI.

For eaxample:

$di->set('output', function () {
        return new \Library\Output;
    });