Data fixture attribute
Overview
Data fixture attributes apply fixtures that implement Magento\TestFramework\Fixture\DataFixtureInterface
or Magento\TestFramework\Fixture\RevertibleDataFixtureInterface
.
It takes two more optional parameters alongside the fixture class name.
The second parameter is the data that is used to customize the fixture and the third parameter is the alias (ID) of the fixture that is used to retrieve the data returned by the fixture and also as a reference in other fixture parameters.
Use data fixtures to prepare a database for tests. The Integration Testing Framework (ITF) reverts the database to its initial state automatically.
To set up a date fixture, use the DataFixture
attribute.
Format
1
2
3
#[
DataFixture(string $type, array $data = [], ?string $as = null)
]
Parameters
- type
- Name of a class that implements
Magento\TestFramework\Fixture\DataFixtureInterface
orMagento\TestFramework\Fixture\RevertibleDataFixtureInterface
.
- Name of a class that implements
- data
- The optional array of data passed on to the fixture.
- as
- The fixture alias that will be used as a reference to retrieve the data returned by the fixture and also as a reference in other fixtures parameters.
Fixture Usage
Retrieve fixture data in the test
A test can retrieve data that was returned by a Data Fixture using Magento\TestFramework\Fixture\DataFixtureStorageManager
and the fixture alias.
The following example shows how to retrieve data that was returned by the fixtures:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ProductsList extends \PHPUnit\Framework\TestCase
{
#[
DataFixture(ProductFixture::class, as: 'product1'),
DataFixture(ProductFixture::class, as: 'product2'),
DataFixture(ProductFixture::class, as: 'product3')
]
public function testGetProductsCount(): void
{
$fixtures = DataFixtureStorageManager::getStorage();
$product1 = $fixtures->get('product1');
$product2 = $fixtures->get('product2');
$product3 = $fixtures->get('product3');
}
}
Supply data to data fixture as a variable
It is possible to supply data as a variable from one fixture to another using the fixture alias in one of the following formats:
$fixtureAlias$
is a reference to the data that was returned by the fixture with aliasfixtureAlias
.$fixtureAlias.snake_case_property_name$
is a reference to the propertysnake_case_property_name
in the data that was returned by the fixture with aliasfixtureAlias
.
The following example shows how a fixture can use the data of another fixture:
1
2
3
4
5
6
7
8
9
10
class QuoteTest extends \PHPUnit\Framework\TestCase
{
#[
DataFixture(GuestCartFixture::class, as: 'cart'),
DataFixture(SetBillingAddressFixture::class, ['cart_id' => '$cart.id$']),
]
public function testCollectTotals(): void
{
}
}
Test class and test method scopes
The DataFixture
can be specified for a particular test or for an entire test case.
The basic rules for fixture attributes at different levels are:
DataFixture
at a test case level makes the framework apply the declared fixtures to each test in the test case. When the final test is complete, all class-level fixtures are reverted.DataFixture
for a particular test signals the framework to revert the fixtures declared on a test case level and applies the fixtures declared at a test method level instead. When the test is complete, the ITF reverts the applied fixtures.
The integration testing framework interacts with a database to revert the applied fixtures.
Creating the fixture
Data Fixture is a PHP class that implements Magento\TestFramework\Fixture\DataFixtureInterface
or Magento\TestFramework\Fixture\RevertibleDataFixtureInterface
. Its main purpose is to seed the database with the data needed to run a test.
Principles
- Data Fixture class MUST implement
Magento\TestFramework\Fixture\DataFixtureInterface
orMagento\TestFramework\Fixture\RevertibleDataFixtureInterface
if the data created by the fixture is revertible. For instance, a fixture that creates an entity (for example, product). - Data Fixture class MUST be placed in the
<ModuleName>/Test/Fixture
folder of the corresponding module with namespace:<VendorName>\<ModuleName>\Test\Fixture
(for example,Magento\Catalog\Test\Fixture
). - Data Fixture class SHOULD follow single responsibility principle.
- Data Fixture class MUST depend only on services from modules that are declared in the
require
section of its module’s composer.json file. - Data Fixture MUST NOT depend on another fixture.
- Data Fixture SHOULD be implemented using service APIs.
- Data Fixture SHOULD have dynamic default data to allow generating unique fixtures.
Dynamic default data
In order to generate multiple fixtures of the same type without having to manually configure unique fields, you can use the placeholder %uniqid%
in the default value of unique fields and Magento\TestFramework\Fixture\Data\ProcessorInterface
to substitute the placeholder with a unique sequence.
Magento\Catalog\Test\Fixture\Product
demonstrates the usage of %uniqid%
(sku
: simple-product%uniqid%
) in the fixture default data.
In the following example, a unique sku
is automatically generated for the first fixture (for example, simple-product61c10b2e86f991
) and the second fixture (for example, simple-product61c10b2e86f992
). The sequence is random and therefore unpredictable.
1
2
3
4
5
6
7
8
9
10
class ProductsListTest extends \PHPUnit\Framework\TestCase
{
#[
DataFixture(ProductFixture::class),
DataFixture(ProductFixture::class)
]
public function testGetProductsCount(): void
{
}
}
Decoupling fixtures
Fixtures must be written in the way that they only use one API to generate data. For example, the fixture that creates a product should only invoke the “Create Product” API and return the product created. This fixture should not add any extra logic beyond the “create product” API capabilities, such logic should be implemented in a separate fixture.
Examples
Example 1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class QuoteTest extends \PHPUnit\Framework\TestCase
{
#[
DataFixture(ProductFixture::class, as: 'p'),
DataFixture(GuestCartFixture::class, as: 'cart'),
DataFixture(AddProductToCartFixture::class, ['cart_id' => '$cart.id$', 'product_id' => '$p.id$', 'qty' => 2]),
DataFixture(SetBillingAddressFixture::class, ['cart_id' => '$cart.id$']),
DataFixture(SetShippingAddressFixture::class, ['cart_id' => '$cart.id$']),
]
public function testCollectTotals(): void
{
}
}
Example 2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class PriceTest extends \PHPUnit\Framework\TestCase
{
#[
DataFixture(ProductFixture::class, ['sku' => 'simple1', 'price' => 10], 'p1'),
DataFixture(ProductFixture::class, ['sku' => 'simple2', 'price' => 20], 'p2'),
DataFixture(ProductFixture::class, ['sku' => 'simple3', 'price' => 30], 'p3'),
DataFixture(BundleSelectionFixture::class, ['sku' => '$p1.sku$', 'price' => 10, 'price_type' => 0], 'link1'),
DataFixture(BundleSelectionFixture::class, ['sku' => '$p2.sku$', 'price' => 25, 'price_type' => 1], 'link2'),
DataFixture(BundleSelectionFixture::class, ['sku' => '$p3.sku$', 'price' => 25, 'price_type' => 0], 'link3'),
DataFixture(BundleOptionFixture::class, ['product_links' => ['$link1$', '$link2$', '$link3$']], 'opt1'),
DataFixture(
BundleProductFixture::class,
['sku' => 'bundle1','price' => 50,'price_type' => 1,'_options' => ['$opt1$']],
'bundle1'
),
]
public function testBundleWithFixedPrice(): void
{
}
}
Fixture rollback
A fixture that contains database transactions only are reverted automatically.
Otherwise, when a fixture creates files or performs any actions other than a database transaction, provide the corresponding rollback logic,
in the revert
method of the revertible data fixture.
Rollbacks are run after reverting all the fixtures related to database transactions.
See the Magento\Catalog\Test\Fixture\Product
fixture for an example.
Restrictions
Do not rely on and do not modify an application state from within a fixture. The application isolation attribute can reset the application state at any time.