Skip to main content

The developers at Magento Contribution Day recommended running unit tests before code deploying. The reasons are: it saves lots of time while testing and the quality of code becomes better. The code will be without errors or errors will be expected. Every function will work no matter what returning data type it receives. It knows how to process any data type. And it means that the function can be applied anywhere.

Magento Documentation for Unit Tests:

  • http://devdocs.magento.com/guides/v2.0/test/testing.html
  • http://devdocs.magento.com/guides/v2.0/test/unit/unit_test_execution.html
  • http://devdocs.magento.com/guides/v2.0/test/unit/writing_testable_code.html
  • http://devdocs.magento.com/guides/v2.0/config-guide/cli/config-cli-subcommands-test.html

PHP Unit this is the php framework  https://phpunit.de/

It helps to find code errors, to fix them and doing code refactoring.
It should cover all programme paths.
One unit test covers one path in a function.

Producer is a testing method that gives a testing unit as a returning value.
Consumer is a testing method that is dependent on one or more producers and their returning values.

Most classes are inherited from the class PHPUnit\Framework\TestCase

The tests have public methods that called test* (it seems that it is the main method, it also can be marked as @test in a comment). The tests methods have a method assertEquals(). This method is used for confirmation of sending value correspondence to the expected one.

Unit test creation: step-by-step instruction

  1. Put it into your module’s folder by the path Test\Unit\. The folders Block, Helper, Model should be located in the same way as in the module folder. For example: Magento\Catalog\Test\Unit\Helper\ProductTest.php
  2. Inherit from \PHPUnit\Framework\TestCase
  3. Create 3 methods:
    – setUp()
    – test* (the mane of the testing unit itself, for example: testIsDataForPriceIndexerWasChanged)
    – @dataProvider method
  4. Specify the path for the testing unit in setUp
  5. Point the expected result in dataProvider
  6. Compare the expected results with the results of checking using an assertEquals function in test*.

Get more specific information at PhpUnit manual
Use it also for better understanding of ready-to-use Magento tests.

Here’s one more instruction How to write Unit test in Magento 2

You can run the tests via PhpStorm or console.

Local settings for PhpStorm:

php-storm-settings-768x4211-1 How to Work Correctly with Unit Tests in Magentosettings-unit-test-1-768x3401-1 How to Work Correctly with Unit Tests in Magento

Debugging of the unit tests in PhpStorm can be done via clicking right button on the file with the test’s class (choose debug test)

Using Console (see more at Run tests for a specific module in Magento2):

Magento 2 use phpunit framework for running test. You can run test per type and module with command:

{phpunit_executable} -c {Magentoroot}/dev/test/{type}/phpunit.xml[.dist] path/to/module/test/dir

For example:

to run unit test for Catalog, you need run command

vendor/phpunit/phpunit/phpunit -c dev/tests/unit/phpunit.xml.dist app/code/Magento/Catalog/Test/Unit/

to run integration test for Catalog, you need run vendor/phpunit/phpunit/phpunit -c dev/tests/integration/phpunit.xml.dist dev/tests/integration/testsuite/Magento/Catalog

Currently only unit test moved to modules. Also static and integration integrity test is working with all magento code.

My own “research” of Unit tests:

If to analyze the class that was used for the test by the developer at Magento Contribution Day, we’ll see:

  1. class XsdTest extends \PHPUnit\Framework\TestCase is inherited from \PHPUnit\Framework\TestCase
  2. there are 2 test* methods: testSchemaCorrectlyIdentifiesInvalidXml and testSchemaCorrectlyIdentifiesValidXml
  3. One of them contains the method assertEquals (testSchemaCorrectlyIdentifiesInvalidXml), the other one contains method assertEmpty (testSchemaCorrectlyIdentifiesValidXml)

If to analyze the whole class (every line and function):

The class has 2 options that are set into the method setUp.

  • $this->_xsdSchema = $urnResolver->getRealPath(‘urn:magento:framework:Event/etc/events.xsd’);
  • $this->_xsdValidator = new \Magento\Framework\TestFramework\Unit\Utility\XsdValidator();

The method testSchemaCorrectlyIdentifiesValidXml:

  • doesn’t have incoming parameters;
  • it is set in the option $xmlString. The content of the file valid_events.xml is taken (it locates in /lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/valid_events.xml, there are specified the names variants of the possible events).
  • The option $actualResult is set. The method validate of the class \Magento\Framework\TestFramework\Unit\Utility\XsdValidator is taken. It receives the parameters /lib/internal/Magento/Framework/Event/etc/events.xsd and the content /lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/valid_events.xml (then they are compared by the function validateDomDocument). The function validate brings back the array $errors.
  • assertEmpty brings back the errors if $errors isn’t empty (the function has the unrequired parameter $message that is brought back if the first one parameter isn’t empty).

The method testSchemaCorrectlyIdentifiesInvalidXml:

  • it has 2 parameters: $xmlString and $expectedError
  • the option $actualError is set. The function validate from the class Magento\Framework\TestFramework\Unit\Utility\XsdValidator compares lib/internal/Magento/Framework/Event/etc/events.xsd with incoming parameter $xmlString
  • the method assertEquals is applied. It compares the expected error (it is incoming parameter $expectedError) with received error $actualError
  • the comment of the function’s description has @dataProvider schemaCorrectlyIdentifiesInvalidXmlDataProvider

The method schemaCorrectlyIdentifiesInvalidXmlDataProvider

  • it brings back /lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/invalidEventsXmlArray.php (the array with errors and errors messages)

SetUp function:

  • checks for the presence the function libxml_set_external_entity_loader
  • sets $urnResolver = new \Magento\Framework\Config\Dom\UrnResolver(); there is the function getRealPath that helps to get the path urn:magento:framework:Event/etc/events.xsd (it is set in xml in the parameter xsi:noNamespaceSchemaLocation=)

Debugging of the Unit tests

Debugging of the unit tests in PhpStorm can be done via clicking right button on the file with the test’s class (choose debug test)

  1. @dataProvider function returns an array which contains an xml string and a text of an error.
  2. schemaCorrectlyIdentifiesInvalidXml is a @dataProvider for the testSchemaCorrectlyIdentifiesInvalidXml method with two parameters: $xmlString and $expectedError. These parameters are taken from the array which @dataProvider returns. The testSchemaCorrectlyIdentifiesInvalidXml method compares the data that was returned by @dataProvider with a message after validation an xml string. In ths case validation messages are generated with an xml.

Setup method:

This is a hookmethod that isn’t present in the documentation. It is an empty method which name is set in emptyHookMethodsArray in vendor/phpunit/phpunit/src/Util/Test.php.

hookmethods-768x5851-1 How to Work Correctly with Unit Tests in Magento

The order of calls priority can be checked in runBare class \PHPUnit\Framework\TestCase.
These methods are suitable for adding custom parameters.

I noticed that classes’ variables are set in SetUp.

Then testSchemaCorrectlyIdentifiesInvalidXml is called.
Then testSchemaCorrectlyIdentifiesInvalidXml and setUp are called until the array @dataProvider is finished.
Finally, testSchemaCorrectlyIdentifiesValidXml is called.

Vladimir Repalo

Vladimir Repalo

Magento Developer at Mobecls, 8+ years of experience. Feel free to ask me anything about this post in the comments below.