Skip to content

Commit 9caafe2

Browse files
Deprecate using a non-static method as a data provider
1 parent 61febda commit 9caafe2

File tree

62 files changed

+1235
-1278
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1235
-1278
lines changed

Diff for: ChangeLog-10.0.md

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ All notable changes of the PHPUnit 10.0 release series are documented in this fi
3535
* [#4599](https://github.com/sebastianbergmann/phpunit/issues/4599): Unify cache configuration
3636
* [#4603](https://github.com/sebastianbergmann/phpunit/issues/4603): Use "property" instead of "attribute" for configuring the backup of static fields
3737
* [#4656](https://github.com/sebastianbergmann/phpunit/issues/4656): Prevent doubling of `__destruct()`
38+
* Using a non-static method as a data provider is now deprecated
39+
* Declaring a data provider method to require an argument is now deprecated
3840
* PHPUnit no longer invokes a static method named `suite` on a class that is declared in a file that is passed as an argument to the CLI test runner
3941
* PHPUnit no longer promotes variables that are global in the bootstrap script's scope to global variables in the test runner's scope (use `$GLOBALS['variable'] = 'value'` instead of `$variable = 'value'` in your bootstrap script)
4042
* `PHPUnit\Framework\TestCase::$backupGlobals` can no longer be used to enable or disable the backup/restore of global and super-global variables for a test case class

Diff for: src/Event/Value/Test/TestDox.php

+16-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,22 @@ public static function fromTestCase(TestCase $testCase): self
3838
);
3939
}
4040

41-
public function __construct(string $prettifiedClassName, string $prettifiedMethodName, string $prettifiedAndColorizedMethodName)
41+
/**
42+
* @psalm-param class-string $className
43+
* @psalm-param non-empty-string $methodName
44+
*/
45+
public static function fromClassNameAndMethodName(string $className, string $methodName): self
46+
{
47+
$prettifier = new NamePrettifier;
48+
49+
return new self(
50+
$prettifier->prettifyTestClassName($className),
51+
$prettifier->prettifyTestMethodName($methodName),
52+
$prettifier->prettifyTestMethodName($methodName),
53+
);
54+
}
55+
56+
private function __construct(string $prettifiedClassName, string $prettifiedMethodName, string $prettifiedAndColorizedMethodName)
4257
{
4358
$this->prettifiedClassName = $prettifiedClassName;
4459
$this->prettifiedMethodName = $prettifiedMethodName;

Diff for: src/Event/Value/Test/TestMethod.php

+17-44
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,17 @@
99
*/
1010
namespace PHPUnit\Event\Code;
1111

12-
use function class_exists;
12+
use function assert;
1313
use function is_int;
1414
use function is_numeric;
15-
use function method_exists;
1615
use function sprintf;
1716
use PHPUnit\Event\TestData\DataFromDataProvider;
1817
use PHPUnit\Event\TestData\MoreThanOneDataSetFromDataProviderException;
1918
use PHPUnit\Event\TestData\NoDataSetFromDataProviderException;
2019
use PHPUnit\Event\TestData\TestDataCollection;
2120
use PHPUnit\Framework\TestCase;
2221
use PHPUnit\Metadata\MetadataCollection;
23-
use PHPUnit\Metadata\Parser\Registry as MetadataRegistry;
24-
use ReflectionException;
25-
use ReflectionMethod;
22+
use PHPUnit\Util\Reflection;
2623
use SebastianBergmann\Exporter\Exporter;
2724

2825
/**
@@ -36,6 +33,10 @@ final class TestMethod extends Test
3633
* @psalm-var class-string
3734
*/
3835
private readonly string $className;
36+
37+
/**
38+
* @psalm-var non-empty-string
39+
*/
3940
private readonly string $methodName;
4041
private readonly int $line;
4142
private readonly TestDox $testDox;
@@ -47,21 +48,26 @@ final class TestMethod extends Test
4748
*/
4849
public static function fromTestCase(TestCase $testCase): self
4950
{
50-
$location = self::sourceLocationFor($testCase::class, $testCase->name());
51+
$methodName = $testCase->name();
52+
53+
assert(!empty($methodName));
54+
55+
$location = Reflection::sourceLocationFor($testCase::class, $methodName);
5156

5257
return new self(
5358
$testCase::class,
54-
$testCase->name(),
59+
$methodName,
5560
$location['file'],
5661
$location['line'],
5762
TestDox::fromTestCase($testCase),
58-
self::metadataFor($testCase::class, $testCase->name()),
63+
MetadataCollection::for($testCase::class, $methodName),
5964
self::dataFor($testCase),
6065
);
6166
}
6267

6368
/**
6469
* @psalm-param class-string $className
70+
* @psalm-param non-empty-string $methodName
6571
*/
6672
public function __construct(string $className, string $methodName, string $file, int $line, TestDox $testDox, MetadataCollection $metadata, TestDataCollection $testData)
6773
{
@@ -83,6 +89,9 @@ public function className(): string
8389
return $this->className;
8490
}
8591

92+
/**
93+
* @psalm-return non-empty-string
94+
*/
8695
public function methodName(): string
8796
{
8897
return $this->methodName;
@@ -186,40 +195,4 @@ private static function dataFor(TestCase $testCase): TestDataCollection
186195

187196
return TestDataCollection::fromArray($testData);
188197
}
189-
190-
private static function metadataFor(string $className, string $methodName): MetadataCollection
191-
{
192-
if (class_exists($className)) {
193-
if (method_exists($className, $methodName)) {
194-
return MetadataRegistry::parser()->forClassAndMethod($className, $methodName);
195-
}
196-
197-
return MetadataRegistry::parser()->forClass($className);
198-
}
199-
200-
return MetadataCollection::fromArray([]);
201-
}
202-
203-
/**
204-
* @psalm-param class-string $className
205-
*
206-
* @psalm-return array{file: string, line: int}
207-
*/
208-
private static function sourceLocationFor(string $className, string $methodName): array
209-
{
210-
try {
211-
$reflector = new ReflectionMethod($className, $methodName);
212-
213-
$file = $reflector->getFileName();
214-
$line = $reflector->getStartLine();
215-
} catch (ReflectionException) {
216-
$file = 'unknown';
217-
$line = 0;
218-
}
219-
220-
return [
221-
'file' => $file,
222-
'line' => $line,
223-
];
224-
}
225198
}

Diff for: src/Framework/TestBuilder.php

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
final class TestBuilder
2828
{
2929
/**
30+
* @psalm-param non-empty-string $methodName
31+
*
3032
* @throws InvalidDataProviderException
3133
*/
3234
public function build(ReflectionClass $theClass, string $methodName): Test

Diff for: src/Framework/TestSuite.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,8 @@ protected function addTestMethod(ReflectionClass $class, ReflectionMethod $metho
552552
$className = $class->getName();
553553
$methodName = $method->getName();
554554

555+
assert(!empty($methodName));
556+
555557
try {
556558
$test = (new TestBuilder)->build($class, $methodName);
557559
} catch (InvalidDataProviderException $e) {
@@ -563,10 +565,9 @@ protected function addTestMethod(ReflectionClass $class, ReflectionMethod $metho
563565
$methodName,
564566
$class->getFileName(),
565567
$method->getStartLine(),
566-
new TestDox(
567-
$prettifier->prettifyTestClassName($className),
568-
$prettifier->prettifyTestMethodName($methodName),
569-
$prettifier->prettifyTestMethodName($methodName),
568+
TestDox::fromClassNameAndMethodName(
569+
$className,
570+
$methodName
570571
),
571572
MetadataCollection::fromArray([]),
572573
Event\TestData\TestDataCollection::fromArray([])

Diff for: src/Metadata/Api/DataProvider.php

+64-5
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,16 @@
2626
use function strlen;
2727
use function substr;
2828
use function trim;
29+
use PHPUnit\Event;
30+
use PHPUnit\Event\Code\TestMethod;
31+
use PHPUnit\Event\TestData\MoreThanOneDataSetFromDataProviderException;
32+
use PHPUnit\Event\TestData\TestDataCollection;
2933
use PHPUnit\Framework\InvalidDataProviderException;
3034
use PHPUnit\Metadata\DataProvider as DataProviderMetadata;
3135
use PHPUnit\Metadata\MetadataCollection;
3236
use PHPUnit\Metadata\Parser\Registry;
3337
use PHPUnit\Metadata\TestWith;
38+
use PHPUnit\Util\Reflection;
3439
use ReflectionClass;
3540
use ReflectionMethod;
3641
use Throwable;
@@ -43,6 +48,7 @@ final class DataProvider
4348
{
4449
/**
4550
* @psalm-param class-string $className
51+
* @psalm-param non-empty-string $methodName
4652
*
4753
* @throws InvalidDataProviderException
4854
*/
@@ -56,7 +62,7 @@ public function providedData(string $className, string $methodName): ?array
5662
}
5763

5864
if ($dataProvider->isNotEmpty()) {
59-
$data = $this->dataProvidedByMethods($dataProvider);
65+
$data = $this->dataProvidedByMethods($className, $methodName, $dataProvider);
6066
} else {
6167
$data = $this->dataProvidedByMetadata($testWith);
6268
}
@@ -82,9 +88,12 @@ public function providedData(string $className, string $methodName): ?array
8288
}
8389

8490
/**
91+
* @psalm-param class-string $className
92+
* @psalm-param non-empty-string $methodName
93+
*
8594
* @throws InvalidDataProviderException
8695
*/
87-
private function dataProvidedByMethods(MetadataCollection $dataProvider): array
96+
private function dataProvidedByMethods(string $className, string $methodName, MetadataCollection $dataProvider): array
8897
{
8998
$result = [];
9099

@@ -94,16 +103,39 @@ private function dataProvidedByMethods(MetadataCollection $dataProvider): array
94103
try {
95104
$class = new ReflectionClass($_dataProvider->className());
96105
$method = $class->getMethod($_dataProvider->methodName());
106+
$object = null;
107+
108+
if (!$method->isStatic()) {
109+
Event\Facade::emitter()->testTriggeredPhpunitDeprecation(
110+
$this->valueObjectForTestMethodWithoutTestData(
111+
$className,
112+
$methodName,
113+
),
114+
sprintf(
115+
'Data Provider method %s::%s() is not static',
116+
$_dataProvider->className(),
117+
$_dataProvider->methodName()
118+
)
119+
);
97120

98-
if ($method->isStatic()) {
99-
$object = null;
100-
} else {
101121
$object = $class->newInstanceWithoutConstructor();
102122
}
103123

104124
if ($method->getNumberOfParameters() === 0) {
105125
$data = $method->invoke($object);
106126
} else {
127+
Event\Facade::emitter()->testTriggeredPhpunitDeprecation(
128+
$this->valueObjectForTestMethodWithoutTestData(
129+
$className,
130+
$methodName,
131+
),
132+
sprintf(
133+
'Data Provider method %s::%s() expects an argument',
134+
$_dataProvider->className(),
135+
$_dataProvider->methodName()
136+
)
137+
);
138+
107139
$data = $method->invoke($object, $_dataProvider->methodName());
108140
}
109141
} catch (Throwable $e) {
@@ -207,4 +239,31 @@ private function dataProvidedByTestWithAnnotation(string $className, string $met
207239

208240
return $data;
209241
}
242+
243+
/**
244+
* @psalm-param class-string $className
245+
* @psalm-param non-empty-string $methodName
246+
*
247+
* @throws MoreThanOneDataSetFromDataProviderException
248+
*/
249+
private function valueObjectForTestMethodWithoutTestData(string $className, string $methodName): TestMethod
250+
{
251+
$location = Reflection::sourceLocationFor($className, $methodName);
252+
253+
return new TestMethod(
254+
$className,
255+
$methodName,
256+
$location['file'],
257+
$location['line'],
258+
Event\Code\TestDox::fromClassNameAndMethodName(
259+
$className,
260+
$methodName
261+
),
262+
MetadataCollection::for(
263+
$className,
264+
$methodName
265+
),
266+
TestDataCollection::fromArray([])
267+
);
268+
}
210269
}

Diff for: src/Metadata/MetadataCollection.php

+20
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@
1111

1212
use function array_filter;
1313
use function array_merge;
14+
use function class_exists;
1415
use function count;
16+
use function method_exists;
1517
use Countable;
1618
use IteratorAggregate;
19+
use PHPUnit\Metadata\Parser\Registry as MetadataRegistry;
1720

1821
/**
1922
* @internal This class is not covered by the backward compatibility promise for PHPUnit
@@ -27,6 +30,23 @@ final class MetadataCollection implements Countable, IteratorAggregate
2730
*/
2831
private readonly array $metadata;
2932

33+
/**
34+
* @psalm-param class-string $className
35+
* @psalm-param non-empty-string $methodName
36+
*/
37+
public static function for(string $className, string $methodName): self
38+
{
39+
if (class_exists($className)) {
40+
if (method_exists($className, $methodName)) {
41+
return MetadataRegistry::parser()->forClassAndMethod($className, $methodName);
42+
}
43+
44+
return MetadataRegistry::parser()->forClass($className);
45+
}
46+
47+
return self::fromArray([]);
48+
}
49+
3050
/**
3151
* @psalm-param list<Metadata> $metadata
3252
*/

Diff for: src/Util/Reflection.php

+25
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,38 @@
1212
use PHPUnit\Framework\Assert;
1313
use PHPUnit\Framework\TestCase;
1414
use ReflectionClass;
15+
use ReflectionException;
1516
use ReflectionMethod;
1617

1718
/**
1819
* @internal This class is not covered by the backward compatibility promise for PHPUnit
1920
*/
2021
final class Reflection
2122
{
23+
/**
24+
* @psalm-param class-string $className
25+
* @psalm-param non-empty-string $methodName
26+
*
27+
* @psalm-return array{file: string, line: int}
28+
*/
29+
public static function sourceLocationFor(string $className, string $methodName): array
30+
{
31+
try {
32+
$reflector = new ReflectionMethod($className, $methodName);
33+
34+
$file = $reflector->getFileName();
35+
$line = $reflector->getStartLine();
36+
} catch (ReflectionException) {
37+
$file = 'unknown';
38+
$line = 0;
39+
}
40+
41+
return [
42+
'file' => $file,
43+
'line' => $line,
44+
];
45+
}
46+
2247
/**
2348
* @psalm-return list<ReflectionMethod>
2449
*/

0 commit comments

Comments
 (0)