IntegrationTesting

Running Integration Tests on Magento 2

The preferred way of writing test in Magento 2 is to use Integration tests. These are similar to Unit tests, but provide you with access to the database and fixtures. In order to run these Magento will install a clean version of the database and reinstall itself. Unfortunately, some modules do not take this into account and will cause problems that prevent this task from completing. At this point you will be unable to run any integration tests without fixing or bypassing these problems.

Identifying the cause of the problem

The first thing to do is to try and run a single test. Create a new phpunit.xml file in the dev/tests/integration/ folder and configure it. For more details on how to do this, follow this guide.

When you run the test you will get a large screen of errors, the line that you are looking for is near the bottom of it and will look something like this

1
2
Next Magento\Framework\Exception\LocalizedException: Command returned non-zero exit code:
`/usr/bin/php -f '/var/www/vhosts/magento2/bin/magento' setup:install -vvv --db-host='localhost' --db-user='root' --db-password='Ap_hpZUJwS9o4oggCUYMNAxWGUGk18DT' --db-name='magento_integration_tests' --backend-frontname='backend' --admin-user='user' --admin-password='password1' --admin-email='admin@example.com' --admin-firstname='firstname' --admin-lastname='lastname' --magento-init-params='MAGE_DIRS[etc][path]=/var/www/vhosts/magento2/dev/tests/integration/tmp/sandbox-0-58d40347945c8a2db0fd6f07b204c9282fe9744e251280aa5aad1f14fb7caee8/etc&MAGE_DIRS[var][path]=/var/www/vhosts/magento2/dev/tests/integration/tmp/sandbox-0-58d40347945c8a2db0fd6f07b204c9282fe9744e251280aa5aad1f14fb7caee8/var&MAGE_DIRS[media][path]=/var/www/vhosts/magento2/dev/tests/integration/tmp/sandbox-0-58d40347945c8a2db0fd6f07b204c9282fe9744e251280aa5aad1f14fb7caee8/pub/media&MAGE_DIRS[static][path]=/var/www/vhosts/magento2/dev/tests/integration/tmp/sandbox-0-58d40347945c8a2db0fd6f07b204c9282fe9744e251280aa5aad1f14fb7caee8/pub/static&MAGE_DIRS[view_preprocessed][path]=/var/www/vhosts/magento2/dev/tests/integration/tmp/sandbox-0-58d40347945c8a2db0fd6f07b204c9282fe9744e251280aa5aad1f14fb7caee8/var/view_preprocessed/pub/static&MAGE_DIRS[code][path]=/var/www/vhosts/magento2/dev/tests/integration/tmp/sandbox-0-58d40347945c8a2db0fd6f07b204c9282fe9744e251280aa5aad1f14fb7caee8/generated/code&MAGE_DIRS[cache][path]=/var/www/vhosts/magento2/dev/tests/integration/tmp/sandbox-0-58d40347945c8a2db0fd6f07b204c9282fe9744e251280aa5aad1f14fb7caee8/var/cache&MAGE_DIRS[log][path]=/var/www/vhosts/magento2/dev/tests/integration/tmp/sandbox-0-58d40347945c8a2db0fd6f07b204c9282fe9744e251280aa5aad1f14fb7caee8/var/log&MAGE_DIRS[session][path]=/var/www/vhosts/magento2/dev/tests/integration/tmp/sandbox-0-58d40347945c8a2db0fd6f07b204c9282fe9744e251280aa5aad1f14fb7caee8/var/session&MAGE_DIRS[tmp][path]=/var/www/vhosts/magento2/dev/tests/integration/tmp/sandbox-0-58d40347945c8a2db0fd6f07b204c9282fe9744e251280aa5aad1f14fb7caee8/var/tmp&MAGE_DIRS[upload][path]=/var/www/vhosts/magento2/dev/tests/integration/tmp/sandbox-0-58d40347945c8a2db0fd6f07b204c9282fe9744e251280aa5aad1f14fb7caee8/var/upload&MAGE_DIRS[pub][path]=/var/www/vhosts/magento2/dev/tests/integration/tmp/sandbox-0-58d40347945c8a2db0fd6f07b204c9282fe9744e251280aa5aad1f14fb7caee8/pub&MAGE_MODE=developer' 2>&1` in /var/www/vhosts/magento2/vendor/magento/framework/Shell.php:64

Copy the command and run it. It will attempt to install Magento, and will error again, however at this point you will be able to configure which modules should be installed. Open the dev/tests/integration/tmp/sandbox-HASH/etc/config.php file and disable all non Magento modules. Then before running the script again do the following:

  • Drop and recreate the database
  • Delete the generated and cache folders in the sandbox
  • Delete the etc/env.php file in the sandbox

Once these have been done you can run the command again and Magento should install successfully. Not you will be doing these tasks quite frequently, so it makes sense to create a script to handle this.

After Magento has been installed, you can update the config file and start turning on Module one by one. Each time one is enabled rerun the install script and see if it succeeds. Once it fails move onto the next step, however keep coming back to this until all of the modules are installed and are passing.

Finding out the cause of the problem

A common problem is that the install command will fail on this step, with a database error saying that a table does not exist.

1
2
[Progress: 4 / 997]
Installing database schema:

This normally means that the module has a console command that has a dependency on something that needs to access the database. The first step is to identify the class that is causing the problem, the second is to fix it.

Identify the problem

In order to speed this up, we need to make some core code hacks. This gives us a more detailed error message and will help us identify the class that is causing problems.

We need to edit the Developer Object Manager and update the create method. Replace the bottom half of the method with the following (from line 58 downwards)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
        try {
            $args = $this->_resolveArguments($requestedType, $parameters, $arguments);
            unset($this->creationStack[$requestedType]);
        } catch (\Exception $e) {
            unset($this->creationStack[$requestedType]);
            throw new \Exception("Error creating $requestedType " . $e->getMessage(), 5, $e);
            throw $e;
        }

        try {
        return $this->createObject($type, $args);
        } catch (\Exception $e) {
            throw new \Exception("Error creating $requestedType " . $e->getMessage(), 5, $e);
        }

With this in place run the install command and again and you will get an Exception like the following:

1
2
3
4
5
6
[Exception(5)]

  Error creating Magento\Framework\Console\CommandList Error creating Vendor\Module\Commands\ExampleCommand
  Error creating Vendor\Module\Model\Cron Error creating Vendor\Module\Helper\Data Error creating   
  Magento\Framework\Stdlib\DateTime\DateTime SQLSTATE[42S02]: Base table or view not found: 1146 Table
  'magento_integration_tests.store_website' doesn't exist, query was: SELECT `store_website`.* FROM `store_website` 

Based on the above we now know what is causing the problem, so we can fix it using a stand alone module to override the DI parameters.

Fixing the problem

Create a new module and add the following to the di.xml file

1
2
3
4
5
6
7
8
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Vendor\Module\Commands\ExampleCommand">
        <arguments>
            <argument name="cron" xsi:type="object">Vendor\Module\Model\Cron\Proxy</argument>
        </arguments>
    </type>
</config>

The important things to note from the above are:

  • The name argument of the type tag should be the FQN of the class that is causing the problem
  • The name argument of the argument tag should be the name of the variable of the class that is causing problems in the __constructor
  • The Vendor\Module\Model\Cron\Proxy argument should be the FQN of the class with \Proxy added to the end, Magento will create this class automatically.

Once this is in place run the install command again, and hopefully Magento should install. If not check the error and see if it is different, you may have to make multiple overrides for a module.

Repeat this process for each module that causes problems until the install command runs successfully. At this point you should be able to run the full test command and have your test pass.

My Fixtures don't work

https://github.com/magento/magento2/issues/18668