2

What would be the most simple setup to create controller integration tests for Magento 1 custom module without the Ecomdev module ?

5
  • PHPunit is for unit tests no? Perhaps you could use BehatMage or something instead
    – scrowler
    Commented Jun 22, 2016 at 8:18
  • @RobbieAverill PHPUnit can be used for integration tests as well. Just check the native Magento 2 integration tests ;) Commented Jun 22, 2016 at 8:20
  • I know it can, just questioning whether it should be :-)
    – scrowler
    Commented Jun 22, 2016 at 8:21
  • @RobbieAverill well I assume that if M2 dev team uses PHPUnit for integration tests I don't see why it shouldn't ^^ Commented Jun 22, 2016 at 8:22
  • I don't want to start a debate as its off topic here, but I think an integration test implies you are testing connections between units, whereas unit testing should only test units, and PHPUnit is for unit tests. Then again, you could argue that your example is actually a unit test anyway!
    – scrowler
    Commented Jun 22, 2016 at 8:25

1 Answer 1

4

Thanks to Vinai's help here's a basic config that will let you create integration tests for your Magento 1 module.

Every file created below will be under app/code/<codePool>/Vendor/Module/Test

Helper and configuration

First you need a phpunit.xml.dist:

<?xml version="1.0"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
         colors="true"
         bootstrap="bootstrap.php"
         backupGlobals="false"
         verbose="true"
>
    <testsuites>
        <testsuite name="Module Integration Tests">
            <directory suffix="Test.php">.</directory>
        </testsuite>
    </testsuites>

</phpunit>

Then you need to create a simple bootstrap.php file to be able to access Mage

<?php

ini_set('display_errors', 1);
error_reporting(E_ALL | E_STRICT);

require __DIR__ . '/../../../../../../app/Mage.php';

function fix_error_handler()
{
    $mageErrorHandler = set_error_handler(function () {
        return false;
    });
    set_error_handler(function ($errno, $errstr, $errfile) use ($mageErrorHandler) {
        if (substr($errfile, -19) === 'Varien/Autoload.php') {
            return null;
        }
        return is_callable($mageErrorHandler) ?
            call_user_func_array($mageErrorHandler, func_get_args()) :
            false;
    });
}
fix_error_handler();
Mage::app();
Mage::setIsDeveloperMode(true);
fix_error_handler();
$_SESSION = [];

Now you need a small controller helper that'll be used to dispatch the requests correctly, I usually create it under Test/Controller/ControllerTestHelper.php :

<?php

class Vendor_Module_Test_Controller_ControllerTestHelper {

    final protected function dispatchRequest($module, $controller, $action)
    {
        $request = Mage::app()->getRequest();
        $request->setModuleName($module);
        $request->setControllerName($controller);
        $request->setActionName($action);

        Mage::app()->getStore()->setConfig('web/url/redirect_to_base', false);
        Mage::app()->getFrontController()->dispatch();
    }

    final public function dispatchPostRequest($module, $controller, $action)
    {
        $_SERVER['REQUEST_METHOD'] = 'POST';
        $this->dispatchRequest($module, $controller, $action);
    }

    final public function dispatchGetRequest($module, $controller, $action)
    {
        $_SERVER['REQUEST_METHOD'] = 'GET';
        $this->dispatchRequest($module, $controller, $action);
    }
}

Finally the last thing you need is a custom HTTP response to avoid the output being flushed in the console and avoid errors such as the headers already sent.

Test/Controller/HttpResponse :

<?php

class Vendor_Module_Test_Controller_HttpResponse extends \Mage_Core_Controller_Response_Http {

    public function canSendHeaders($throw = false)
    {
        return true;
    }

    public function sendHeaders()
    {
        return $this;
    }

    public function sendResponse()
    {
        $this->sendHeaders();

        if ($this->isException() && $this->renderExceptions()) {
            $exceptions = '';
            foreach ($this->getException() as $e) {
                $exceptions .= $e->__toString() . "\n";
            }
            echo $exceptions;
            return;
        }

        // Don't flush the output
        //$this->outputBody();
        // Return it instead
        return $this->_body;
    }
}

First Test

Ready for the first test, don't forget the suffix declared in phpunit.xml.dist

So you can create Test/Controller/MyControllerTest.php :

<?php

class Vendor_Module_Test_Controller_MyControllerTest extends \PHPUnit_Framework_TestCase {

    public function setUp()
    {
        // Stub response to avoid headers already sent problems
        $stubResponse = new \Vendor_Module_Test_Controller_HttpResponse();
        Mage::app()->setResponse($stubResponse);

        // Use a controller helper
        $controllerTestHelper = new \Vendor_Module_Test_Controller_ControllerTestHelper($this);
        // Dispatch the request
        $controllerTestHelper->dispatchGetRequest('custom', 'module', 'route');
    }

    public function testSomething()
    {
        // Get the header
        $headers = Mage::app()->getResponse()->getHeaders();

        // Get the response
        $response = Mage::app()->getResponse()->getBody(true);

        // Test something
    }
}

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.