Automated test types in Magento / Adobe Commerce
● Unit Tests
● Integration Tests
● Functional Tests (MFTF)
● API Functional Tests
● Static Tests
● …and more
Full list of supported test types:
https://developer.adobe.com/commerce/testing/guide/
Integration Tests - basic info
● Very similar to Unit Tests in architecture
● Based on PHPUnit
● Use the built-in Integration Tests Framework
● Require access to services that Magento requires for installation (database,
redis, search engine etc.)
● Require some initial setup in config files
Integration Tests - types
We can identify two types of Integration Tests:
- End-to-end or cross-component tests: tests that simulate full path of some
use case, like registering a customer, adding a product to cart, filling shipping
and billing data, placing an order and checking if it got persisted in the
database with no errors
- Component tests: tests that usually involve only one class along with its
dependencies; something that a lot of people would consider a Unit Test for
Setting up
1. Create an empty database
2. Copy two .dist files in dev/tests/integration/etc/ to the same directory, but without the .dist extension:
a. install-config-mysql.php.dist
b. config-global.php.dist
3. Edit your new install-config-mysql.php file and adjust all the settings for database connection, redis
connection etc.
4. Do not touch admin credentials or frontname as some tests may fail because of that
5. If you have any global config settings that all your tests require, put them in config-global.php
6. Copy dev/test/quick-integration/phpunit.xml.dist to dev/tests/quick-integration/phpunit.xml and
disable TESTS_CLEANUP to speed up subsequent executions (the app won’t try to reinstall)
Run your tests using the following command from the Magento dev/tests/integration directory:
php ../../../vendor/bin/phpunit ../../../some/directory/to/test
Anatomy of a test
This is how a simple Integration Test looks like:
Integration Tests Framework - Annotations
The following annotations are available in integration tests:
● @magentoAppIsolation
● @magentoDbIsolation
● @magentoDataFixture
● @magentoDataFixtureBeforeTransaction
● @magentoAppArea
● @magentoConfigFixture
There are less commonly used ones too, the full list is available here:
https://developer.adobe.com/commerce/testing/guide/integration/annotations/
Annotations - Example
Please note that there are two different ways of defining a data fixture:
● The first one defines a path relative to a module
● The second one defines a path relative to dev/tests/integration/testsuite
There are tons of useful fixtures in dev/tests/integration/testsuite.
Integration Tests vs Unit Tests
Unit Tests Integration Tests
Dependent on tested code implementation Independent of implementation - they only care about results
Require A LOT of mocks Don’t require mocks - can work with “real” classes. Can still
use mocks if required.
Require a lot of maintenance effort Don’t require a lot of maintenance effort
Can only work with PHP classes Can also test validity of the XML-based configuration layer
Can only test in isolation Can test in as much isolation as the developer wants
Hard to predict during a task creation Can be easily defined as parts of acceptance criteria
Run VERY fast Run VERY slow*
Limited possibility of testing code that interacts with 3rd party
services
Limited possibility of testing code that interacts with 3rd party
services*
* Can be improved
Integration Tests vs Unit Tests - let’s talk numbers…
Customer repository - unit test class Customer repository - integration test class
82 lines of setUp() 15 lines of setUp()
173 lines of testSave() 20 lines of testCreateNewCustomer() which also tests save();
No need for an explicit testSave()
57 mocks in the class 0 mocks in the class, only actual test logic
742 lines of code in the class for 5 tests: delete, deleteById,
getList, save and saveWithPassworHash
692 lines of code to perform 14 different tests
mocks returning mocks all objects created by the object manager
Example of how to define tests during task creation
Task #1: Admins should see ERP invoice issuer on the invoice view page in
Magento admin panel
Description: When an invoice is manually created in ERP, it has the creator’s
name attached. We are already pulling this data and now we need to show it in
Magento admin panel. Invoices that have this data should display “Issuer: Name
Here” and those that don’t should not display this info at all.
Tests: easy to define both Unit and Integration tests during the task creation, as
this will require a template override and either a ViewModel or a preference for the
block to pull the data from the database.
Example of how to define tests during task creation
Now imagine that the initial implementation of the Task #1 example was made
using a preference for the block displaying this data, but later on it got refactored
to a view model.
Integration tests will still work.
Example of how to define tests during task creation
Task #2: Customers can’t place orders above $10,000
Description: No customer is able to place an order above $10k. Those same
customers can successfully place orders below or equal $10k with the same data
(addresses, shipping and billing method etc.).
Integration Tests: Create a quote for above $10k, use it to place orders. Watch it
fail, then fix the issue.
Unit Tests: ???
Integration Tests - issues and how to avoid them
Two main issues are:
● Long execution time
● Limited help with testing code that connects with 3rd party services
Solution:
ReachDigital Magento 2 Performance tuned integration tests
https://github.com/ho-nl/magento2-ReachDigital_TestFramework
Integration Tests - with the ReachDigital component
Fix for the issue #1 - long execution time:
● Disabled memory cleanup scripts
● Made the application to not reinitialize that much
● Disabled config-global.php usage
● Disabled the sequence table generation
It takes just seconds to run a single test.
Integration Tests - with the ReachDigital component
Fix for the issue #2 - limited possibility of testing code that interacts with 3rd party
services:
● Introduced TestModules
● Every module can have a TestModule directory inside with a fully functional
Magento module
● Those modules are copied to app/code during tests execution and don’t affect
regular (non-test) executions of the Magento application
● Test modules can have preferences and/or around plugins in di.xml for
classes/methods that connect to 3rd party services, and return mocked data
instead
● Limitation: works only for modules inside the vendor directory
Integration Tests - with the ReachDigital component
Setting up:
1. composer require --dev reach-digital/magento2-test-framework
2. Perform the regular setup procedure for integration tests
3. Copy dev/tests/quick-integration/phpunit.xml.dist to dev/tests/quick-
integration/phpunit.xml if you need to change anything there
Running:
Perform the following commands from the Magento root directory:
cd dev/tests/integration
php ../../../vendor/bin/phpunit -c ../quick-integration/phpunit.xml ../../../path/to/test
Conclusions
1. Do test your code
2. Use Integration Tests instead of Unit Tests for better results
3. Consider end-to-end tests for critical paths
4. Use component integration tests for your modules
5. Install the ReachDigital component or else you’ll get bored and abandon the
idea of running Integration Tests