Skip to content

Commit 9fd7f73

Browse files
committed
Refactor data attributes
1 parent 9409d7c commit 9fd7f73

4 files changed

Lines changed: 109 additions & 115 deletions

File tree

blog/data-providers.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ Well, this article wouldn't exist if there was nothing to say.
5050

5151
**First**, I didn't like the `#[TestWith]` attribute name in PHPUnit. It conveys the intent well (*test with "this"*), but what about consistency? I wouldn't have known about this attribute if not by chance (do you know about it?).
5252

53-
::: tip ☝️ It would be better if this attribute appeared in IDE suggestions when typing "Data": next to `DataProvider`.
53+
::: tip ☝️ It would be better if this attribute appeared in IDE suggestions when typing "Data": next to <attr>\Testo\Data\DataProvider</attr>.
5454
:::
5555

56-
That's why in Testo this attribute is named: `#[DataSet]`.
56+
That's why in Testo this attribute is named: <attr>\Testo\Data\DataSet</attr>.
5757

58-
**Second**, Testo has no separate `#[DataProviderExternal]` attribute: the need for it simply disappears, since you can pass any `callable` to `#[DataProvider]`.
58+
**Second**, Testo has no separate `#[DataProviderExternal]` attribute: the need for it simply disappears, since you can pass any `callable` to <attr>\Testo\Data\DataProvider</attr>.
5959

6060
**And third**, datasets in Testo can merge not only vertically, but also horizontally and diagonally.
6161

@@ -120,7 +120,7 @@ Like PHPUnit, Testo expects data providers to return dataset collections: `itera
120120

121121
### Combining Providers
122122

123-
You probably guessed that stacking multiple Data-attributes (`#[DataSet]` and `#[DataProvider]`) on a function will grow the dataset collection, similar to a UNION query in SQL.
123+
You probably guessed that stacking multiple Data-attributes (<attr>\Testo\Data\DataSet</attr> and <attr>\Testo\Data\DataProvider</attr>) on a function will grow the dataset collection, similar to a UNION query in SQL.
124124

125125
```php
126126
#[DataSet([1, 1, 2])]
@@ -129,7 +129,7 @@ You probably guessed that stacking multiple Data-attributes (`#[DataSet]` and `#
129129
public function testSum(int $a, int $b, int $c): void { ... }
130130
```
131131

132-
The test runs for all datasets sequentially: first `[1, 1, 2]` from `DataSet`, then all from `dataSum`, then all from `SomeClass::method()`.
132+
The test runs for all datasets sequentially: first `[1, 1, 2]` from <attr>\Testo\Data\DataSet</attr>, then all from `dataSum`, then all from `SomeClass::method()`.
133133

134134
::: info 🤔 But what if you want to combine datasets in more interesting ways?
135135
:::
@@ -171,18 +171,18 @@ Cartesian product — all possible combinations. Useful when parameters are inde
171171
public function testResponsiveLayout(string $browser, int $width, int $height): void { ... }
172172
```
173173

174-
3 browsers × 3 screen sizes = 9 tests. Three providers with 5 elements each — already 125 tests. `DataCross` grows fast, use wisely.
174+
3 browsers × 3 screen sizes = 9 tests. Three providers with 5 elements each — already 125 tests. <attr>\Testo\Data\DataCross</attr> grows fast, use wisely.
175175

176176
### DataUnion
177177

178178
![DataUnion](/blog/data-providers/union.png)
179179

180-
The `#[DataUnion]` attribute merges multiple providers into one — simply concatenates datasets into a single collection, just like stacking multiple `#[DataProvider]` attributes on a test.
180+
The <attr>\Testo\Data\DataUnion</attr> attribute merges multiple providers into one — simply concatenates datasets into a single collection, just like stacking multiple <attr>\Testo\Data\DataProvider</attr> attributes on a test.
181181

182182
::: info 🫤 Wait, why a separate attribute?
183183
:::
184184

185-
`DataUnion` is needed **inside** `DataCross` or `DataZip`:
185+
<attr>\Testo\Data\DataUnion</attr> is needed **inside** <attr>\Testo\Data\DataCross</attr> or <attr>\Testo\Data\DataZip</attr>:
186186

187187
```php
188188
#[DataCross(

docs/plugins/data.md

Lines changed: 44 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ llms_description: "Parameterized tests: #[DataSet], #[DataProvider] with callabl
66

77
Data providers let you run one test with different sets of input data. Each set runs as a separate test.
88

9-
## DataSet
10-
11-
The simplest way — specify data directly above the method:
12-
9+
<signature h="2" name="#[\Testo\Data\DataSet(array $arguments, ?string $name = null)]">
10+
<short>Declares a set of arguments for a parameterized test. Can be used multiple times — each attribute creates a separate test run.</short>
11+
<param name="$arguments">Array of values passed to the test method.</param>
12+
<param name="$name">Label displayed in reports. Helps identify which scenario failed.</param>
13+
<example>
1314
```php
1415
#[Test]
1516
#[DataSet([1, 1, 2])]
@@ -20,24 +21,23 @@ public function testSum(int $a, int $b, int $expected): void
2021
Assert::same($expected, $a + $b);
2122
}
2223
```
23-
24-
Each `DataSet` is an array of arguments passed to the test method. The test runs three times with different values.
25-
26-
### Dataset Labels
27-
28-
The second argument is an optional label. It appears in reports and helps identify which scenario failed:
24+
</example>
25+
<example>
26+
With labels:
2927

3028
```php
3129
#[DataSet([1, 1, 2], 'positive numbers')]
3230
#[DataSet([-1, -1, -2], 'negative numbers')]
3331
#[DataSet([0, 0, 0], 'zeros')]
3432
public function testSum(int $a, int $b, int $expected): void { ... }
3533
```
34+
</example>
35+
</signature>
3636

37-
## DataProvider
38-
39-
For large amounts of data or dynamic generation, use `DataProvider`. It accepts a method or callable that returns test data:
40-
37+
<signature h="2" name="#[\Testo\Data\DataProvider(callable|string $provider)]">
38+
<short>Provides data for a parameterized test from a method or callable.</short>
39+
<param name="$provider">Data source: method name (`'method'`), callable (`[Class::class, 'method']`), closure, or invokable object. Must return `iterable`. String keys of elements become dataset labels in reports.</param>
40+
<example>
4141
```php
4242
#[Test]
4343
#[DataProvider('userDataProvider')]
@@ -52,13 +52,14 @@ public function userDataProvider(): iterable
5252
yield ['valid@example.com', true];
5353
yield ['invalid', false];
5454
yield ['test@domain.co.uk', true];
55-
// ... 50 more cases
5655
}
5756
```
57+
</example>
58+
</signature>
5859

5960
### Flexible Provider Sources
6061

61-
`DataProvider` accepts various callable types:
62+
<attr>\Testo\Data\DataProvider</attr> accepts various callable types:
6263

6364
**Method name from the same class:**
6465
```php
@@ -104,12 +105,13 @@ public function userDataProvider(): array
104105
}
105106
```
106107

107-
## DataZip
108-
109-
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.
110-
111-
Typical use case — testing related data where each pair forms a meaningful test case:
112-
108+
<signature h="2" name="#[\Testo\Data\DataZip(DataProviderAttribute ...$providers)]">
109+
<short>Pairs up providers element by element.</short>
110+
<description>
111+
The first item from the first provider joins with the first from the second, second with second, and so on. Arguments from all providers merge into a single test call.
112+
</description>
113+
<param name="$providers">Data providers to pair up.</param>
114+
<example>
113115
```php
114116
#[DataZip(
115117
new DataProvider('credentials'),
@@ -128,8 +130,8 @@ public function testUserPermissions(string $login, string $password, array $perm
128130
// 1. admin/secret → ['read', 'write', 'delete']
129131
// 2. guest/1234 → ['read']
130132
```
131-
132-
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`).
133+
</example>
134+
</signature>
133135

134136
### Providers of Different Lengths
135137

@@ -155,10 +157,10 @@ public function testTransform(string $input, string $output): void { ... }
155157
Dataset labels are joined with `|`. If datasets are named `admin` and `full-access`, the report shows `admin|full-access`.
156158
:::
157159

158-
## DataCross
159-
160-
Creates all possible combinations of values from providers (cartesian product). Useful for testing independent parameters that can combine in any way.
161-
160+
<signature h="2" name="#[\Testo\Data\DataCross(DataProviderAttribute ...$providers)]">
161+
<short>Creates all possible combinations from providers (cartesian product).</short>
162+
<param name="$providers">Data providers to combine.</param>
163+
<example>
162164
```php
163165
#[DataCross(
164166
new DataProvider('browsers'),
@@ -179,31 +181,24 @@ public function testResponsiveLayout(string $browser, int $width, int $height):
179181
// chrome × 1920×1080, chrome × 768×1024, chrome × 375×667,
180182
// firefox × 1920×1080, ...
181183
```
184+
</example>
185+
</signature>
182186

183187
::: warning Watch the Combination Count
184-
Test count grows multiplicatively. Three providers with 5 items each means 125 tests. Use `DataCross` mindfully.
188+
Test count grows multiplicatively. Three providers with 5 items each means 125 tests. Use <attr>\Testo\Data\DataCross</attr> mindfully.
185189
:::
186190

187191
::: tip Keys in Reports
188192
Labels are joined with `×`. Datasets `chrome` and `mobile` produce the key `chrome×mobile`.
189193
:::
190194

191-
## DataUnion
192-
193-
To combine data from multiple sources, you can simply list attributes above the method:
194-
195-
```php
196-
#[DataProvider('adminUsers')]
197-
#[DataProvider('regularUsers')]
198-
#[DataSet(['guest'], 'guest')]
199-
public function testUserCanLogin(string $username): void
200-
{
201-
// Runs for all: adminUsers, then regularUsers, then guest
202-
}
203-
```
204-
205-
`DataUnion` is needed when combining must happen inside another attribute — for example, inside `DataCross` or `DataZip`:
206-
195+
<signature h="2" name="#[\Testo\Data\DataUnion(DataProviderAttribute ...$providers)]">
196+
<short>Merges data from multiple providers into a single sequential set.</short>
197+
<description>
198+
To combine data from multiple sources, you can simply list multiple <attr>\Testo\Data\DataProvider</attr> or <attr>\Testo\Data\DataSet</attr> above the method. <attr>\Testo\Data\DataUnion</attr> is needed when combining must happen inside another attribute — for example, inside <attr>\Testo\Data\DataCross</attr> or <attr>\Testo\Data\DataZip</attr>.
199+
</description>
200+
<param name="$providers">Data providers to merge into a single set.</param>
201+
<example>
207202
```php
208203
#[DataCross(
209204
new DataUnion(
@@ -217,12 +212,12 @@ public function testExport(string $format, int $compression): void
217212
// All formats (legacy + modern) are crossed with each compression level
218213
}
219214
```
220-
221-
Without `DataUnion`, you'd have to either create a separate provider that merges formats, or duplicate `DataCross` for each format source.
215+
</example>
216+
</signature>
222217

223218
## Combining Providers
224219

225-
Inside `DataZip`, `DataCross`, and `DataUnion` you can use any data providers — `DataProvider`, `DataSet`, and even nest them within each other.
220+
Inside <attr>\Testo\Data\DataZip</attr>, <attr>\Testo\Data\DataCross</attr>, and <attr>\Testo\Data\DataUnion</attr> you can use any data providers — <attr>\Testo\Data\DataProvider</attr>, <attr>\Testo\Data\DataSet</attr>, and even nest them within each other.
226221

227222
### Mixing Types
228223

@@ -237,7 +232,7 @@ Handy when some parameters are fixed while others come from a provider:
237232
public function testMigration(string $driver, array $scenario): void { ... }
238233
```
239234

240-
Or more compact with a `DataProvider` for drivers:
235+
Or more compact with a <attr>\Testo\Data\DataProvider</attr> for drivers:
241236

242237
```php
243238
#[DataCross(

ru/blog/data-providers.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ public function testSum(int $a, int $b, int $c): void { ... }
5050

5151
**Во-первых**, мне в PHPUnit не понравилось название атрибута `#[TestWith]`. Оно неплохо передаёт намерение (*протестировать с "этим"*), но что насчёт консистентности? Я бы так и не узнал об этом атрибуте, если бы не случайность (а вы знаете о нём?).
5252

53-
::: tip ☝️ Было бы лучше, если бы такой атрибут вылезал в подсказках IDE при вводе слова "Data": рядом с `DataProvider`.
53+
::: tip ☝️ Было бы лучше, если бы такой атрибут вылезал в подсказках IDE при вводе слова "Data": рядом с <attr>\Testo\Data\DataProvider</attr>.
5454
:::
5555

56-
Поэтому в Testo этот атрибут назван: `#[DataSet]`.
56+
Поэтому в Testo этот атрибут назван: <attr>\Testo\Data\DataSet</attr>.
5757

58-
**Во-вторых**, в Testo нет отдельного атрибута `#[DataProviderExternal]`: надобность в нём просто исчезает, поскольку в `#[DataProvider]` можно просто передать любой `callable`.
58+
**Во-вторых**, в Testo нет отдельного атрибута `#[DataProviderExternal]`: надобность в нём просто исчезает, поскольку в <attr>\Testo\Data\DataProvider</attr> можно просто передать любой `callable`.
5959

6060
**И в-третьих**, датасеты в Testo могут мержиться не только вертикально, но и горизонтально, и по-диагонали.
6161

@@ -120,7 +120,7 @@ public function testSum(int $a, int $b, int $c): void { ... }
120120

121121
### Комбинирование провайдеров
122122

123-
Вы, наверное, догадываетесь, что если Data-атрибуты (`#[DataSet]` и `#[DataProvider]`) повесить на функцию несколько раз, то это приведёт к увеличению коллекции датасетов подобно UNION запросу в SQL.
123+
Вы, наверное, догадываетесь, что если Data-атрибуты (<attr>\Testo\Data\DataSet</attr> и <attr>\Testo\Data\DataProvider</attr>) повесить на функцию несколько раз, то это приведёт к увеличению коллекции датасетов подобно UNION запросу в SQL.
124124

125125
```php
126126
#[DataSet([1, 1, 2])]
@@ -129,7 +129,7 @@ public function testSum(int $a, int $b, int $c): void { ... }
129129
public function testSum(int $a, int $b, int $c): void { ... }
130130
```
131131

132-
Тест запустится для всех датасетов последовательно: сначала `[1, 1, 2]` из `DataSet`, затем все из `dataSum`, затем все из `SomeClass::method()`.
132+
Тест запустится для всех датасетов последовательно: сначала `[1, 1, 2]` из <attr>\Testo\Data\DataSet</attr>, затем все из `dataSum`, затем все из `SomeClass::method()`.
133133

134134
::: info 🤔 Но что, если хочется соединить датасеты как-то поинтереснее?
135135
:::
@@ -171,18 +171,18 @@ public function testDeletePermission(string $user, bool $expected): void { ... }
171171
public function testResponsiveLayout(string $browser, int $width, int $height): void { ... }
172172
```
173173

174-
3 браузера × 3 разрешения = 9 тестов. Три провайдера по 5 элементов — уже 125 тестов. `DataCross` растёт быстро, используйте осознанно.
174+
3 браузера × 3 разрешения = 9 тестов. Три провайдера по 5 элементов — уже 125 тестов. <attr>\Testo\Data\DataCross</attr> растёт быстро, используйте осознанно.
175175

176176
### DataUnion
177177

178178
![DataUnion](/blog/data-providers/union.png)
179179

180-
Атрибут `#[DataUnion]` Объединяет несколько провайдеров в один — просто склеивает датасеты в общую коллекцию наравне с тем, как если бы несколько `#[DataProvider]` были повешены на тест.
180+
Атрибут <attr>\Testo\Data\DataUnion</attr> объединяет несколько провайдеров в один — просто склеивает датасеты в общую коллекцию наравне с тем, как если бы несколько <attr>\Testo\Data\DataProvider</attr> были повешены на тест.
181181

182182
::: info 🫤 Стоп, а зачем отдельный атрибут?
183183
:::
184184

185-
`DataUnion` нужен **внутри** `DataCross` или `DataZip`:
185+
<attr>\Testo\Data\DataUnion</attr> нужен **внутри** <attr>\Testo\Data\DataCross</attr> или <attr>\Testo\Data\DataZip</attr>:
186186

187187
```php
188188
#[DataCross(

0 commit comments

Comments
 (0)