ARTICLE

Automated Testing for Magento 2 Modules: PHPUnit and MFTF in CI to Keep Customizations From Breaking on Upgrade

Automated Testing for Magento 2 Modules: PHPUnit and MFTF in CI to Keep Customizations From Breaking on Upgrade

Automated tests keep a Magento 2 customization from breaking silently on upgrade. Run unit and integration tests with bin/magento dev:tests:run for your module’s logic, use MFTF for black-box browser flows, add static analysis, and wire all of it into CI so every pull request and every upgrade candidate runs the suite before it ever reaches production.

Every Magento team has felt it. An upgrade to the next patch release goes out, the smoke test looks fine, and three days later a customer cannot apply a discount or a B2B quote silently fails. The customization that broke was never covered by a test, so nothing caught the regression until a real order did. Automated testing is how you stop shipping that surprise, and Magento 2 ships a full testing framework for exactly this. This guide covers the test layers that matter, how to run them, and how to put them in a pipeline so upgrades stop being a gamble. Bemeir builds and maintains Magento and Adobe Commerce stores, and this is the testing approach we hold our own module work to.

Why upgrade safety is really a testing problem

Magento customizations attach to core behavior. A plugin wraps a core method, a preference replaces a class, an observer listens for an event. When Adobe ships an upgrade that changes a method signature, renames an event, or alters a return type, your customization can keep running against an interface that no longer behaves the way it did. Nothing throws an error at deploy time. The behavior just quietly changes.

Manual QA does not reliably catch this, because no human clicks through every edge case on every release, and the broken path is usually the uncommon one. Automated tests do, because they assert the exact behavior you depend on and fail the moment it changes. That is why testing, not a careful release checklist, is the real answer to “will this upgrade break us.” A disciplined release pipeline is the delivery half, and tests are what give it something to gate on.

The Magento 2 test layers that matter

Adobe’s application testing guide documents several test types. Five of them do the real work of protecting a customization.

  • Unit tests check isolated PHP logic without the full application stack. They are fast and are where you cover algorithms, calculations, and branching.
  • Integration tests run PHP code with the real dependency injection container and database, at varying degrees of isolation but with no browser. This is the layer that catches upgrade breakage.
  • API functional tests exercise REST, SOAP, and GraphQL from a client’s point of view, which matters when your module exposes or depends on web APIs.
  • Functional tests (MFTF) drive a real browser to test the storefront and admin as a user would.
  • Static tests check the code itself against coding standards and include PHPStan analysis.

Unit and integration tests both run through bin/magento dev:tests:run, and so do the static checks. Knowing which layer to put a given assertion in is most of the skill, so take them in order of cost.

Unit tests: fast, isolated, where you start

Unit tests live in each module’s Test/Unit directory and extend PHPUnit’s TestCase. They mock every dependency so the test exercises one class in isolation, which keeps them fast enough to run on every save. You run all of them with bin/magento dev:tests:run unit, or point PHPUnit at a single module’s directory using the framework’s config file at dev/tests/unit/phpunit.xml.dist when you want a tight loop on one class.

Unit tests are the right home for business logic: a price calculation, a tax rule, a method that decides whether a customer qualifies for a shipping band. If the logic has branches, each branch deserves an assertion. What unit tests cannot tell you is whether your class still wires up correctly against the rest of Magento, because everything around it is mocked. For that you need the next layer.

Integration tests: the layer that catches upgrade breakage

Integration tests live in dev/tests/integration and run your code against a real dependency injection container and a real database, without a browser. This is the single highest-value layer for upgrade safety, because it exercises the seams where your customization meets core Magento.

If your plugin wraps Magento\Catalog\Model\Product::getPrice and an upgrade changes how that method behaves, an integration test that asserts the final price for a known product will fail on the upgrade candidate, in CI, before anyone merges. That is the whole game: the test fails in a pull request instead of in production. Integration tests are slower than unit tests because they bootstrap the framework, so you do not write hundreds of them, but a focused set covering each customization’s contract with core is the best insurance an upgrade budget can buy. They run through the same bin/magento dev:tests:run entry point, and understanding plugins, observers, and preferences tells you which seams need this coverage most.

MFTF: black-box browser tests for the flows you cannot afford to break

The Functional Testing Framework is Magento’s tool for end-to-end browser testing. Per Adobe’s framework documentation, it performs automated end-to-end functional testing from a user’s perspective, treating the application as a black box. Version 3.0 ships with Adobe Commerce and Magento Open Source 2.4, tests are written as declarative XML steps, and under the hood it drives a real browser with Selenium and Codeception. Results can be rendered as visual reports with Allure.

MFTF tests live in each module’s Test/Mftf folder. You install the framework as a Composer dependency, build it with vendor/bin/mftf build:project, and run a test with vendor/bin/mftf run:test. Because browser tests are slow and more fragile than PHP tests, reserve MFTF for the journeys that must never break: add to cart, checkout, place order, B2B quote submission, account creation. Do not try to cover every field with it. A handful of MFTF tests on your revenue-critical flows catches the failures that cost money, while unit and integration tests carry the bulk of the coverage. The same black-box logic on the Hyva frontend is covered in our guide to testing Alpine.js interactions with Playwright.

Static analysis and PHPStan: cheap insurance on every file

Static tests never run your code; they read it. Run them with bin/magento dev:tests:run static, and they apply PhpCs and PhpMd coding-standard checks plus dependency and legacy-code checks. Adobe’s unit and static testing guidance sits alongside this layer. PHPStan is part of the static suite and runs on changed PHP files at rule level 1, finding undefined properties, undefined methods, and type mismatches that would otherwise surface as runtime errors. It is configured in phpstan.neon, and specific lines can be suppressed when a false positive is unavoidable.

Static analysis is the cheapest test you will ever run and it catches a surprising share of upgrade problems, because a renamed core method shows up as an undefined-method error before any test even executes. Put it first in the pipeline so a failing static check stops the build in seconds.

Wiring it into CI so upgrades run the suite automatically

Tests on a developer’s laptop protect no one. The point is to run them automatically on every pull request and every upgrade candidate. A workable pipeline looks like this:

  1. On every pull request, run static analysis, then unit tests, then the integration tests that cover your customizations. These are fast enough to gate a merge.
  2. On merge to the main branch, and nightly, run the MFTF suite against a built instance.
  3. When an upgrade is proposed, run the full suite against the upgraded codebase. A red build is your answer.

For MFTF at scale, Adobe’s CI/CD guidance describes splitting tests into roughly equal groups with vendor/bin/mftf generate:tests --config parallel, running each node’s group with vendor/bin/mftf run:manifest, re-running only failures with vendor/bin/mftf run:failed, and collecting results into an Allure report. Splitting across nodes is what keeps a browser suite from turning a pipeline into an hour-long wait.

Test layers at a glance

Layer Scope Speed When to run
Static / PHPStan Code standards, type errors on changed files Seconds Every pull request, first
Unit One class, dependencies mocked Fast Every pull request
Integration Real DI and database, no browser Moderate Every pull request, on each customization’s seams
API functional REST, SOAP, GraphQL endpoints Moderate On API-exposing modules, and on upgrade
MFTF functional Full browser journeys Slow On merge, nightly, and on upgrade candidates

A realistic testing policy for an agency build

You do not need total coverage. You need coverage where failure costs money and where upgrades most often break things. A practical policy: unit tests on every piece of business logic, integration tests on every seam where a customization touches core, MFTF on the handful of revenue-critical flows, and static analysis on everything, all running in CI on every change. That is enough to turn an upgrade from a nervous weekend into a green build.

This discipline is part of why upgrades go smoothly for merchants we support, whether they run Adobe Commerce or sell on Shopify, Shopware, or BigCommerce, and it is the same rigor behind our Hyva work and the tooling we draw from our technology partner ecosystem. When the next release lands, tested customizations are the difference between a routine update and an outage, which is exactly the problem our guide to upgrading to Magento 2.4.8 exists to help you plan for.

If your Magento customizations have no test coverage and every upgrade feels like a risk, Bemeir can help you build a suite and a pipeline around them, and you can read more about Bemeir and how we work.

FAQ

What is the difference between unit and integration tests in Magento 2?

Unit tests check one class in isolation with every dependency mocked, so they are fast but cannot tell you whether your code wires up correctly against the rest of Magento. Integration tests run against the real dependency injection container and database, which is slower but is what catches a customization breaking when a core upgrade changes behavior underneath it.

How do I run Magento’s tests from the command line?

Use bin/magento dev:tests:run with a type such as unit, integration, or static. For a single module’s unit tests during development, point PHPUnit at that module’s Test/Unit directory using the config at dev/tests/unit/phpunit.xml.dist. MFTF browser tests run separately through vendor/bin/mftf.

Do I need MFTF, or are PHPUnit tests enough?

Most coverage should be unit and integration tests, because they are fast and cover logic and core seams. MFTF is worth the extra cost only for the handful of end-to-end browser journeys you cannot afford to break, such as checkout and order placement. Use it sparingly on critical flows rather than trying to cover the whole site with it.

How does testing prevent upgrade regressions specifically?

Integration tests assert the exact behavior your customizations depend on, running against the real framework. When an upgrade changes a core method your plugin or preference relies on, the test fails in CI on the upgrade candidate instead of in production. Static analysis adds a second net by flagging undefined or renamed methods before the code even runs.

Where should a team with no tests start?

Start with static analysis and a few integration tests on your most important customizations, then add unit tests as you touch each class. Static checks cost almost nothing to add and catch real problems immediately, and a small set of integration tests on revenue-critical logic gives you upgrade protection quickly without needing full coverage on day one.

Let us help you get started on a project with Automated Testing for Magento 2 Modules: PHPUnit and MFTF in CI to Keep Customizations From Breaking on Upgrade and leverage our partnership to your fullest advantage. Fill out the contact form below to get started.

more articles about ecommerce

Read on the latest with Shopify, Magento, eCommerce topics and more.