Skip to content

Commit eb1e3a0

Browse files
authored
Merge pull request #7893 from magento-l3/ACP2E-1131
ACP2E-1131: Parametrized Fixtures Improvements
2 parents e8f1b89 + 7cd7862 commit eb1e3a0

File tree

10 files changed

+193
-48
lines changed

10 files changed

+193
-48
lines changed

dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/AddSimpleProductToCartSingleMutationTest.php

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
use Magento\Quote\Model\QuoteIdToMaskedQuoteIdInterface;
1212
use Magento\Quote\Test\Fixture\AddProductToCart as AddProductToCartFixture;
1313
use Magento\Quote\Test\Fixture\GuestCart as GuestCartFixture;
14+
use Magento\Store\Test\Fixture\Group as StoreGroupFixture;
15+
use Magento\Store\Test\Fixture\Store as StoreFixture;
16+
use Magento\Store\Test\Fixture\Website as WebsiteFixture;
1417
use Magento\TestFramework\Fixture\DataFixture;
1518
use Magento\TestFramework\Fixture\DataFixtureStorage;
1619
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
@@ -219,18 +222,27 @@ public function testAddProductWithWrongQuantity(int $quantity, string $message)
219222
}
220223

221224
/**
222-
* @magentoApiDataFixture Magento/Catalog/_files/products_with_websites_and_stores.php
223-
* @magentoApiDataFixture Magento/Checkout/_files/active_quote.php
224-
* @magentoApiDataFixture Magento/Checkout/_files/active_quote_not_default_website.php
225225
* @dataProvider addProductNotAssignedToWebsiteDataProvider
226-
* @param string $reservedOrderId
227-
* @param string $sku
226+
* @param string $cart
227+
* @param string $product
228228
* @param array $headerMap
229229
*/
230-
public function testAddProductNotAssignedToWebsite(string $reservedOrderId, string $sku, array $headerMap)
230+
#[
231+
DataFixture(WebsiteFixture::class, as: 'website2'),
232+
DataFixture(StoreGroupFixture::class, ['website_id' => '$website2.id$'], 'store_group2'),
233+
DataFixture(StoreFixture::class, ['store_group_id' => '$store_group2.id$'], 'store2'),
234+
DataFixture(ProductFixture::class, ['website_ids' => [1]], as: 'product1'),
235+
DataFixture(ProductFixture::class, ['website_ids' => ['$website2.id$']], as: 'product2'),
236+
DataFixture(GuestCartFixture::class, as: 'cart1'),
237+
DataFixture(GuestCartFixture::class, as: 'cart2', scope: 'store2'),
238+
]
239+
public function testAddProductNotAssignedToWebsite(string $cart, string $product, array $headerMap)
231240
{
232-
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
241+
$sku = $this->fixtures->get($product)->getSku();
242+
$cartId = (int) $this->fixtures->get($cart)->getId();
243+
$maskedQuoteId = $this->quoteIdToMaskedQuoteIdInterface->execute($cartId);
233244
$query = $this->getAddToCartMutation($maskedQuoteId, 1, $sku);
245+
$headerMap = array_map(fn ($store) => $this->fixtures->get($store)?->getCode() ?? $store, $headerMap);
234246
$response = $this->graphQlMutation($query, [], '', $headerMap);
235247
self::assertEmpty($response['addProductsToCart']['cart']['items']);
236248
self::assertArrayHasKey('user_errors', $response['addProductsToCart']);
@@ -386,9 +398,9 @@ public function testAddMultipleProductsWithInsufficientStockToEmptyCart(): void
386398
public function addProductNotAssignedToWebsiteDataProvider(): array
387399
{
388400
return [
389-
['test_order_1', 'simple-2', []],
390-
['test_order_1', 'simple-2', ['Store' => 'default']],
391-
['test_order_2', 'simple-1', ['Store' => 'fixture_second_store']],
401+
['cart1', 'product2', []],
402+
['cart1', 'product2', ['Store' => 'default']],
403+
['cart2', 'product1', ['Store' => 'store2']],
392404
];
393405
}
394406

dev/tests/integration/framework/Magento/TestFramework/Annotation/DataFixtureSetup.php

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,23 @@
1313
use Magento\TestFramework\Fixture\DataFixtureFactory;
1414
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
1515
use Magento\TestFramework\Fixture\RevertibleDataFixtureInterface;
16+
use Magento\TestFramework\ScopeSwitcherInterface;
1617

1718
/**
1819
* Apply and revert data fixtures
1920
*/
2021
class DataFixtureSetup
2122
{
22-
/**
23-
* @var Registry
24-
*/
25-
private $registry;
26-
27-
/**
28-
* @var DataFixtureFactory
29-
*/
30-
private $dataFixtureFactory;
31-
3223
/**
3324
* @param Registry $registry
3425
* @param DataFixtureFactory $dataFixtureFactory
26+
* @param ScopeSwitcherInterface $scopeSwitcher
3527
*/
3628
public function __construct(
37-
Registry $registry,
38-
DataFixtureFactory $dataFixtureFactory
29+
private Registry $registry,
30+
private DataFixtureFactory $dataFixtureFactory,
31+
private ScopeSwitcherInterface $scopeSwitcher
3932
) {
40-
$this->registry = $registry;
41-
$this->dataFixtureFactory = $dataFixtureFactory;
4233
}
4334

4435
/**
@@ -51,7 +42,17 @@ public function apply(array $fixture): ?DataObject
5142
{
5243
$data = $this->resolveVariables($fixture['data'] ?? []);
5344
$factory = $this->dataFixtureFactory->create($fixture['factory']);
54-
$result = $factory->apply($data);
45+
if (isset($fixture['scope'])) {
46+
$scope = DataFixtureStorageManager::getStorage()->get($fixture['scope']);
47+
$fromScope = $this->scopeSwitcher->switch($scope);
48+
try {
49+
$result = $factory->apply($data);
50+
} finally {
51+
$this->scopeSwitcher->switch($fromScope);
52+
}
53+
} else {
54+
$result = $factory->apply($data);
55+
}
5556

5657
if ($result !== null && !empty($fixture['name'])) {
5758
DataFixtureStorageManager::getStorage()->persist(

dev/tests/integration/framework/Magento/TestFramework/Fixture/DataFixture.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,18 @@
1313
class DataFixture
1414
{
1515
/**
16-
* @param string $type
17-
* @param array $data
18-
* @param string|null $as
16+
* @param string $type Fixture class name
17+
* @param array $data Data passed on to the fixture.
18+
* @param string|null $as Fixture identifier used to retrieve the data returned by the fixture
19+
* @param string|null $scope Name of scope data fixture in which the data fixture should be executed
20+
* @param int $count Number of instances to generate
1921
*/
2022
public function __construct(
2123
public string $type,
2224
public array $data = [],
23-
public ?string $as = null
25+
public ?string $as = null,
26+
public ?string $scope = null,
27+
public int $count = 1
2428
) {
2529
}
2630
}

dev/tests/integration/framework/Magento/TestFramework/Fixture/Parser/DataFixture.php

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ public function __construct(
3535
*/
3636
public function parse(TestCase $test, string $scope): array
3737
{
38-
$fixtures = [];
3938
try {
4039
$reflection = $scope === ParserInterface::SCOPE_CLASS
4140
? new \ReflectionClass($test)
@@ -50,14 +49,22 @@ public function parse(TestCase $test, string $scope): array
5049
);
5150
}
5251

52+
$fixtures = [];
5353
$attributes = $reflection->getAttributes($this->attributeClass);
5454
foreach ($attributes as $attribute) {
5555
$args = $attribute->getArguments();
56-
$fixtures[] = [
57-
'name' => $args['as'] ?? $args[2] ?? null,
58-
'factory' => $args[0],
59-
'data' => $args[1] ?? [],
60-
];
56+
$alias = $args['as'] ?? $args[2] ?? null;
57+
$count = $args['count'] ?? $args[4] ?? 1;
58+
$id = $count > 1 ? 1 : '';
59+
do {
60+
$fixtures[] = [
61+
'name' => $alias !== null ? ($alias.($id++)) : null,
62+
'factory' => $args[0],
63+
'data' => $args[1] ?? [],
64+
'scope' => $args['scope'] ?? $args[3] ?? null,
65+
];
66+
} while (--$count > 0);
67+
6168
}
6269
return $fixtures;
6370
}

dev/tests/integration/framework/Magento/TestFramework/ObjectManager/Configurator.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
use Magento\Store\Model\StoreManagerInterface;
1111
use Magento\Framework\App\MutableScopeConfig;
1212
use Magento\Framework\App\ReinitableConfig;
13-
use Magento\Framework\App\Config as AppConfig;
1413
use Magento\Backend\App\Config as BackendConfig;
14+
use Magento\TestFramework\ScopeSwitcherInterface;
1515

1616
/**
1717
* Class which hold configurations (preferences, etc...) of integration test framework
@@ -36,6 +36,15 @@ public function getConfiguration()
3636
BackendConfig::class => \Magento\TestFramework\Backend\App\Config::class,
3737
ReinitableConfig::class => \Magento\TestFramework\App\ReinitableConfig::class,
3838
MutableScopeConfig::class => \Magento\TestFramework\App\MutableScopeConfig::class,
39+
ScopeSwitcherInterface::class => \Magento\TestFramework\Store\ScopeSwitcher::class,
40+
],
41+
\Magento\TestFramework\Store\ScopeSwitcher::class => [
42+
'arguments' => [
43+
'storeManager' => [
44+
// @phpstan-ignore-next-line
45+
'instance' => \Magento\Store\Model\StoreManagerInterface\Proxy::class
46+
]
47+
]
3948
]
4049
];
4150
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\TestFramework;
9+
10+
use Magento\Framework\App\ScopeInterface;
11+
12+
interface ScopeSwitcherInterface
13+
{
14+
/**
15+
* Set the current scope to the specified scope
16+
*
17+
* @param ScopeInterface $scope
18+
* @return ScopeInterface previous scope
19+
*/
20+
public function switch(ScopeInterface $scope): ScopeInterface;
21+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\TestFramework\Store;
9+
10+
use Magento\Framework\App\ScopeInterface;
11+
use Magento\Store\Model\StoreManagerInterface;
12+
use Magento\TestFramework\ScopeSwitcherInterface;
13+
14+
class ScopeSwitcher implements ScopeSwitcherInterface
15+
{
16+
/**
17+
* @param StoreManagerInterface $storeManager
18+
*/
19+
public function __construct(
20+
private StoreManagerInterface $storeManager
21+
) {
22+
}
23+
24+
/**
25+
* @inheritDoc
26+
*/
27+
public function switch(ScopeInterface $scope): ScopeInterface
28+
{
29+
$fromStore = $this->storeManager->getStore();
30+
switch ($scope->getScopeType()) {
31+
case \Magento\Store\Model\ScopeInterface::SCOPE_STORE:
32+
case \Magento\Store\Model\ScopeInterface::SCOPE_STORES:
33+
$toStore = $scope->getId();
34+
break;
35+
case \Magento\Store\Model\ScopeInterface::SCOPE_GROUP:
36+
case \Magento\Store\Model\ScopeInterface::SCOPE_GROUPS:
37+
$toStore = $this->storeManager->getGroup($scope->getCode())->getDefaultStoreId();
38+
break;
39+
case \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE:
40+
case \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITES:
41+
$groupId = $this->storeManager->getWebsite($scope->getCode())->getDefaultGroupId();
42+
$toStore = $this->storeManager->getGroup($groupId)->getDefaultStoreId();
43+
break;
44+
default:
45+
throw new \InvalidArgumentException('Invalid scope');
46+
}
47+
$this->storeManager->setCurrentStore($toStore);
48+
return $fromStore;
49+
}
50+
}

dev/tests/integration/framework/Magento/TestFramework/Workaround/Override/Fixture/Resolver.php

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,13 @@ class Resolver implements ResolverInterface
4848
/** @var string */
4949
private $currentFixtureType = null;
5050

51-
/**
52-
* @var DataFixtureSetup
53-
*/
54-
private $dataFixtureSetup;
55-
5651
/**
5752
* @param ConfigInterface $config
5853
*/
5954
public function __construct(ConfigInterface $config)
6055
{
6156
$this->config = $config;
6257
$this->objectManager = Bootstrap::getObjectManager();
63-
$this->dataFixtureSetup = $this->objectManager->create(DataFixtureSetup::class);
6458
}
6559

6660
/**
@@ -122,7 +116,8 @@ public function requireDataFixture(string $path): void
122116
}
123117
/** @var DataFixtureApplier $dataFixtureApplier */
124118
$dataFixtureApplier = $this->getApplier($this->getCurrentTest(), $this->currentFixtureType);
125-
$this->dataFixtureSetup->apply(['factory' => $dataFixtureApplier->replace($path)]);
119+
$dataFixtureSetup = $this->objectManager->create(DataFixtureSetup::class);
120+
$dataFixtureSetup->apply(['factory' => $dataFixtureApplier->replace($path)]);
126121
}
127122

128123
/**

dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/DataFixtureTest.php

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Magento\TestFramework\Fixture\LegacyDataFixture;
2525
use Magento\TestFramework\Fixture\RevertibleDataFixtureInterface;
2626
use Magento\TestFramework\Helper\Bootstrap;
27+
use Magento\TestFramework\ScopeSwitcherInterface;
2728
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
2829
use PHPUnit\Framework\MockObject\MockObject;
2930
use PHPUnit\Framework\TestCase;
@@ -99,11 +100,16 @@ protected function setUp(): void
99100
$dataFixtureFactory = new DataFixtureFactory($objectManager);
100101
$annotationParser = new \Magento\TestFramework\Annotation\Parser\DataFixture('magentoDataFixture');
101102

103+
$dataFixtureSetup = new DataFixtureSetup(
104+
new Registry(),
105+
$dataFixtureFactory,
106+
$this->createMock(ScopeSwitcherInterface::class)
107+
);
102108
$sharedInstances = [
103109
TestsIsolation::class => $this->testsIsolationMock,
104110
\Magento\TestFramework\Annotation\Parser\DataFixture::class => $annotationParser,
105111
DataFixtureFactory::class => $dataFixtureFactory,
106-
DataFixtureSetup::class => new DataFixtureSetup(new Registry(), $dataFixtureFactory),
112+
DataFixtureSetup::class => $dataFixtureSetup,
107113
'MockFixture1' => $this->fixture1,
108114
'MockFixture2' => $this->fixture2,
109115
'MockFixture3' => $this->fixture3,
@@ -484,6 +490,42 @@ public function testVariables(): void
484490
$this->revertFixtures();
485491
}
486492

493+
#[
494+
DbIsolation(false),
495+
DataFixture('MockFixture1', ['p1' => 'param-value1'], 'fixture1', count: 2),
496+
DataFixture('MockFixture2', ['p2' => '$fixture12.attr_1$'], 'fixture2'),
497+
DataFixture('MockFixture3', ['p3' => '$fixture2.attr_3$', 'p4' => ['p5' => '$fixture11$']], 'fixture3'),
498+
]
499+
public function testCount(): void
500+
{
501+
$fixture11 = new DataObject(['attr_1' => 'attr-value11', 'attr_2' => 'attr-value21']);
502+
$fixture12 = new DataObject(['attr_1' => 'attr-value12', 'attr_2' => 'attr-value22']);
503+
$fixture2 = new DataObject(['attr_3' => 1]);
504+
$this->fixture1->expects($this->exactly(2))
505+
->method('apply')
506+
->with(['p1' => 'param-value1'])
507+
->willReturnOnConsecutiveCalls($fixture11, $fixture12);
508+
$this->fixture2->expects($this->once())
509+
->method('apply')
510+
->with(['p2' => 'attr-value12'])
511+
->willReturn($fixture2);
512+
$this->fixture3->expects($this->once())
513+
->method('apply')
514+
->with(['p3' => 1, 'p4' => ['p5' => $fixture11]]);
515+
$this->applyFixtures();
516+
$this->assertSame($fixture11, $this->fixtureStorage->get('fixture11'));
517+
$this->assertSame($fixture12, $this->fixtureStorage->get('fixture12'));
518+
$this->assertSame($fixture2, $this->fixtureStorage->get('fixture2'));
519+
$this->assertNull($this->fixtureStorage->get('fixture3'));
520+
$this->fixture1->expects($this->exactly(2))
521+
->method('revert')
522+
->withConsecutive([$fixture12], [$fixture11]);
523+
$this->fixture2->expects($this->once())
524+
->method('revert')
525+
->with($fixture2);
526+
$this->revertFixtures();
527+
}
528+
487529
/**
488530
* @throws ReflectionException
489531
*/

0 commit comments

Comments
 (0)