Skip to content

Commit aea2845

Browse files
committed
Add DataZip, DataCross, and DataUnion documentation sections
1 parent fed4dc2 commit aea2845

2 files changed

Lines changed: 330 additions & 1 deletion

File tree

docs/data-providers.md

Lines changed: 165 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,168 @@ public function userDataProvider(): array
9898
'empty string' => ['', false],
9999
];
100100
}
101-
```
101+
```
102+
103+
## DataZip
104+
105+
Pairs up multiple providers element by element. The first item from the first provider joins with the first item from the second, second with second, and so on.
106+
107+
Typical use case — testing related data where each pair forms a meaningful test case:
108+
109+
```php
110+
#[DataZip(
111+
new DataProvider('credentials'),
112+
new DataProvider('expectedPermissions'),
113+
)]
114+
public function testUserPermissions(string $login, string $password, array $permissions): void
115+
{
116+
$user = $this->auth->login($login, $password);
117+
Assert::same($permissions, $user->getPermissions());
118+
}
119+
120+
// credentials: [['admin', 'secret'], ['guest', '1234']]
121+
// expectedPermissions: [[['read', 'write', 'delete']], [['read']]]
122+
//
123+
// Test runs 2 times:
124+
// 1. admin/secret → ['read', 'write', 'delete']
125+
// 2. guest/1234 → ['read']
126+
```
127+
128+
Arguments from all providers merge into a single test call. In the example above, `credentials` provides two arguments (`$login`, `$password`), while `expectedPermissions` provides one (`$permissions`).
129+
130+
### Providers of Different Lengths
131+
132+
If providers have different lengths, the number of datasets is determined by the shortest provider:
133+
134+
```php
135+
#[DataZip(
136+
new DataProvider('inputs'), // 3 items
137+
new DataProvider('outputs'), // 2 items
138+
)]
139+
public function testTransform(string $input, string $output): void { ... }
140+
141+
// inputs: [['a'], ['b'], ['c']]
142+
// outputs: [['x'], ['y']]
143+
//
144+
// Runs 2 times (limited by outputs):
145+
// 1. 'a', 'x'
146+
// 2. 'b', 'y'
147+
// Third item from inputs ('c') is ignored
148+
```
149+
150+
::: tip Keys in Reports
151+
Dataset labels are joined with `|`. If datasets are named `admin` and `full-access`, the report shows `admin|full-access`.
152+
:::
153+
154+
## DataCross
155+
156+
Creates all possible combinations of values from providers (cartesian product). Useful for testing independent parameters that can combine in any way.
157+
158+
```php
159+
#[DataCross(
160+
new DataProvider('browsers'),
161+
new DataProvider('screenSizes'),
162+
)]
163+
public function testResponsiveLayout(string $browser, int $width, int $height): void
164+
{
165+
$this->driver->setBrowser($browser);
166+
$this->driver->setViewport($width, $height);
167+
168+
Assert::true($this->page->isLayoutCorrect());
169+
}
170+
171+
// browsers: [['chrome'], ['firefox'], ['safari']]
172+
// screenSizes: [[1920, 1080], [768, 1024], [375, 667]]
173+
//
174+
// Runs 9 times — each browser with each screen size:
175+
// chrome × 1920×1080, chrome × 768×1024, chrome × 375×667,
176+
// firefox × 1920×1080, ...
177+
```
178+
179+
::: warning Watch the Combination Count
180+
Test count grows multiplicatively. Three providers with 5 items each means 125 tests. Use `DataCross` mindfully.
181+
:::
182+
183+
::: tip Keys in Reports
184+
Labels are joined with `×`. Datasets `chrome` and `mobile` produce the key `chrome×mobile`.
185+
:::
186+
187+
## DataUnion
188+
189+
To combine data from multiple sources, you can simply list attributes above the method:
190+
191+
```php
192+
#[DataProvider('adminUsers')]
193+
#[DataProvider('regularUsers')]
194+
#[DataSet(['guest'], 'guest')]
195+
public function testUserCanLogin(string $username): void
196+
{
197+
// Runs for all: adminUsers, then regularUsers, then guest
198+
}
199+
```
200+
201+
`DataUnion` is needed when combining must happen inside another attribute — for example, inside `DataCross` or `DataZip`:
202+
203+
```php
204+
#[DataCross(
205+
new DataUnion(
206+
new DataProvider('legacyFormats'),
207+
new DataProvider('modernFormats'),
208+
),
209+
new DataProvider('compressionLevels'),
210+
)]
211+
public function testExport(string $format, int $compression): void
212+
{
213+
// All formats (legacy + modern) are crossed with each compression level
214+
}
215+
```
216+
217+
Without `DataUnion`, you'd have to either create a separate provider that merges formats, or duplicate `DataCross` for each format source.
218+
219+
## Combining Providers
220+
221+
Inside `DataZip`, `DataCross`, and `DataUnion` you can use any data providers — `DataProvider`, `DataSet`, and even nest them within each other.
222+
223+
### Mixing Types
224+
225+
Handy when some parameters are fixed while others come from a provider:
226+
227+
```php
228+
#[DataCross(
229+
new DataSet(['mysql'], 'mysql'),
230+
new DataSet(['pgsql'], 'pgsql'),
231+
new DataProvider('migrationScenarios'),
232+
)]
233+
public function testMigration(string $driver, array $scenario): void { ... }
234+
```
235+
236+
Or more compact with a `DataProvider` for drivers:
237+
238+
```php
239+
#[DataCross(
240+
new DataProvider('databaseDrivers'),
241+
new DataProvider('migrationScenarios'),
242+
)]
243+
public function testMigration(string $driver, array $scenario): void { ... }
244+
```
245+
246+
### Nested Combinations
247+
248+
For complex scenarios, providers can be nested:
249+
250+
```php
251+
#[DataZip(
252+
new DataCross(
253+
new DataProvider('users'),
254+
new DataProvider('roles'),
255+
),
256+
new DataProvider('expectedResults'),
257+
)]
258+
public function testAccessControl(string $user, string $role, bool $expected): void
259+
{
260+
$this->actAs($user)->withRole($role);
261+
Assert::same($expected, $this->canAccess('/admin'));
262+
}
263+
264+
// users × roles produces all user-role combinations,
265+
// then they're paired with expected results

ru/docs/data-providers.md

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,168 @@ public function userDataProvider(): array
9999
];
100100
}
101101
```
102+
103+
## DataZip
104+
105+
Объединяет несколько провайдеров попарно. Первый элемент из первого провайдера соединяется с первым элементом из второго, второй со вторым, и так далее.
106+
107+
Типичный сценарий — тестирование связанных данных, где каждая пара образует осмысленный тест-кейс:
108+
109+
```php
110+
#[DataZip(
111+
new DataProvider('credentials'),
112+
new DataProvider('expectedPermissions'),
113+
)]
114+
public function testUserPermissions(string $login, string $password, array $permissions): void
115+
{
116+
$user = $this->auth->login($login, $password);
117+
Assert::same($permissions, $user->getPermissions());
118+
}
119+
120+
// credentials: [['admin', 'secret'], ['guest', '1234']]
121+
// expectedPermissions: [[['read', 'write', 'delete']], [['read']]]
122+
//
123+
// Тест запустится 2 раза:
124+
// 1. admin/secret → ['read', 'write', 'delete']
125+
// 2. guest/1234 → ['read']
126+
```
127+
128+
Аргументы из всех провайдеров объединяются в один вызов теста. В примере выше `credentials` даёт два аргумента (`$login`, `$password`), а `expectedPermissions` — один (`$permissions`).
129+
130+
### Провайдеры разной длины
131+
132+
Если провайдеры имеют разную длину, количество датасетов определяется самым коротким провайдером:
133+
134+
```php
135+
#[DataZip(
136+
new DataProvider('inputs'), // 3 элемента
137+
new DataProvider('outputs'), // 2 элемента
138+
)]
139+
public function testTransform(string $input, string $output): void { ... }
140+
141+
// inputs: [['a'], ['b'], ['c']]
142+
// outputs: [['x'], ['y']]
143+
//
144+
// Запустится 2 раза (по длине outputs):
145+
// 1. 'a', 'x'
146+
// 2. 'b', 'y'
147+
// Третий элемент inputs ('c') игнорируется
148+
```
149+
150+
::: tip Ключи в отчётах
151+
Метки датасетов соединяются через `|`. Если датасеты называются `admin` и `full-access`, в отчёте будет `admin|full-access`.
152+
:::
153+
154+
## DataCross
155+
156+
Создаёт все возможные комбинации значений из провайдеров (декартово произведение). Полезно для тестирования независимых параметров, которые могут сочетаться произвольным образом.
157+
158+
```php
159+
#[DataCross(
160+
new DataProvider('browsers'),
161+
new DataProvider('screenSizes'),
162+
)]
163+
public function testResponsiveLayout(string $browser, int $width, int $height): void
164+
{
165+
$this->driver->setBrowser($browser);
166+
$this->driver->setViewport($width, $height);
167+
168+
Assert::true($this->page->isLayoutCorrect());
169+
}
170+
171+
// browsers: [['chrome'], ['firefox'], ['safari']]
172+
// screenSizes: [[1920, 1080], [768, 1024], [375, 667]]
173+
//
174+
// Запустится 9 раз — каждый браузер с каждым разрешением:
175+
// chrome × 1920×1080, chrome × 768×1024, chrome × 375×667,
176+
// firefox × 1920×1080, ...
177+
```
178+
179+
::: warning Следите за количеством комбинаций
180+
Число тестов растёт мультипликативно. Три провайдера по 5 элементов — это уже 125 тестов. Используйте `DataCross` осознанно.
181+
:::
182+
183+
::: tip Ключи в отчётах
184+
Метки соединяются через `×`. Датасеты `chrome` и `mobile` дадут ключ `chrome×mobile`.
185+
:::
186+
187+
## DataUnion
188+
189+
Для объединения данных из нескольких источников обычно достаточно перечислить атрибуты над методом:
190+
191+
```php
192+
#[DataProvider('adminUsers')]
193+
#[DataProvider('regularUsers')]
194+
#[DataSet(['guest'], 'guest')]
195+
public function testUserCanLogin(string $username): void
196+
{
197+
// Запустится для всех: adminUsers, затем regularUsers, затем guest
198+
}
199+
```
200+
201+
`DataUnion` нужен, когда объединение должно произойти внутри другого атрибута — например, внутри `DataCross` или `DataZip`:
202+
203+
```php
204+
#[DataCross(
205+
new DataUnion(
206+
new DataProvider('legacyFormats'),
207+
new DataProvider('modernFormats'),
208+
),
209+
new DataProvider('compressionLevels'),
210+
)]
211+
public function testExport(string $format, int $compression): void
212+
{
213+
// Все форматы (legacy + modern) скрещиваются с каждым уровнем сжатия
214+
}
215+
```
216+
217+
Без `DataUnion` пришлось бы либо создавать отдельный провайдер, объединяющий форматы, либо дублировать `DataCross` для каждого источника форматов.
218+
219+
## Комбинирование провайдеров
220+
221+
Внутри `DataZip`, `DataCross` и `DataUnion` можно использовать любые провайдеры данных — `DataProvider`, `DataSet`, а также вкладывать их друг в друга.
222+
223+
### Смешивание типов
224+
225+
Удобно, когда часть параметров фиксирована, а часть приходит из провайдера:
226+
227+
```php
228+
#[DataCross(
229+
new DataSet(['mysql'], 'mysql'),
230+
new DataSet(['pgsql'], 'pgsql'),
231+
new DataProvider('migrationScenarios'),
232+
)]
233+
public function testMigration(string $driver, array $scenario): void { ... }
234+
```
235+
236+
Или компактнее через `DataProvider` для драйверов:
237+
238+
```php
239+
#[DataCross(
240+
new DataProvider('databaseDrivers'),
241+
new DataProvider('migrationScenarios'),
242+
)]
243+
public function testMigration(string $driver, array $scenario): void { ... }
244+
```
245+
246+
### Вложенные комбинации
247+
248+
Для сложных сценариев провайдеры можно вкладывать:
249+
250+
```php
251+
#[DataZip(
252+
new DataCross(
253+
new DataProvider('users'),
254+
new DataProvider('roles'),
255+
),
256+
new DataProvider('expectedResults'),
257+
)]
258+
public function testAccessControl(string $user, string $role, bool $expected): void
259+
{
260+
$this->actAs($user)->withRole($role);
261+
Assert::same($expected, $this->canAccess('/admin'));
262+
}
263+
264+
// users × roles даёт все комбинации пользователь-роль,
265+
// затем они попарно соединяются с ожидаемыми результатами
266+
```

0 commit comments

Comments
 (0)