From c981c29f6cfda14290c7abb82edd1578dc3210e9 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sat, 14 Nov 2026 18:08:43 +0100 Subject: [PATCH 1/2] [PHPUnit60] Skip tests in classes with own asserting lifecycle methods in AddDoesNotPerformAssertionToNonAssertingTestRector --- .github/workflows/code_analysis.yaml | 4 + ..._not_perform_assertion_lifecycle_bench.php | 28 +++- ..._perform_assertion_own_lifecycle_bench.php | 122 ++++++++++++++++++ .../Fixture/non_asserting_set_up.php.inc | 42 ++++++ .../skip_asserting_after_annotation.php.inc | 21 +++ ...asserting_aliased_before_attribute.php.inc | 20 +++ .../skip_asserting_before_attribute.php.inc | 20 +++ ...serting_hook_after_anonymous_class.php.inc | 26 ++++ ...skip_asserting_own_post_conditions.php.inc | 18 +++ .../Fixture/skip_asserting_set_up.php.inc | 18 +++ .../skip_asserting_set_up_helper.php.inc | 24 ++++ ...rformAssertionToNonAssertingTestRector.php | 22 ++++ src/Enum/PHPUnitAttribute.php | 8 ++ .../LifecycleMethodAssertAnalyzer.php | 95 ++++++++++++++ 14 files changed, 461 insertions(+), 7 deletions(-) create mode 100644 bench/does_not_perform_assertion_own_lifecycle_bench.php create mode 100644 rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/non_asserting_set_up.php.inc create mode 100644 rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_after_annotation.php.inc create mode 100644 rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_aliased_before_attribute.php.inc create mode 100644 rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_before_attribute.php.inc create mode 100644 rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_hook_after_anonymous_class.php.inc create mode 100644 rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_own_post_conditions.php.inc create mode 100644 rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_set_up.php.inc create mode 100644 rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_set_up_helper.php.inc create mode 100644 src/NodeAnalyzer/LifecycleMethodAssertAnalyzer.php diff --git a/.github/workflows/code_analysis.yaml b/.github/workflows/code_analysis.yaml index 5a7c5c1e..f3cbc44b 100644 --- a/.github/workflows/code_analysis.yaml +++ b/.github/workflows/code_analysis.yaml @@ -44,6 +44,10 @@ jobs: name: 'Bench abstract classes' run: php bench/does_not_perform_assertion_abstract_class_bench.php + - + name: 'Bench own lifecycle methods' + run: php bench/does_not_perform_assertion_own_lifecycle_bench.php + name: ${{ matrix.actions.name }} runs-on: ubuntu-latest timeout-minutes: 10 diff --git a/bench/does_not_perform_assertion_lifecycle_bench.php b/bench/does_not_perform_assertion_lifecycle_bench.php index dbfa0808..8bbe0d84 100644 --- a/bench/does_not_perform_assertion_lifecycle_bench.php +++ b/bench/does_not_perform_assertion_lifecycle_bench.php @@ -12,10 +12,12 @@ */ use PhpParser\Node\Stmt\ClassMethod; +use Rector\Application\Provider\CurrentFileProvider; use Rector\DependencyInjection\LazyContainerFactory; use Rector\PhpParser\Node\BetterNodeFinder; use Rector\PHPUnit\PHPUnit60\Rector\ClassMethod\AddDoesNotPerformAssertionToNonAssertingTestRector; use Rector\Testing\TestingParser\TestingParser; +use Rector\ValueObject\Application\File; require __DIR__ . '/../vendor/autoload.php'; @@ -98,11 +100,17 @@ $rector = $rectorConfig->make(AddDoesNotPerformAssertionToNonAssertingTestRector::class); +/** @var CurrentFileProvider $currentFileProvider */ +$currentFileProvider = $rectorConfig->make(CurrentFileProvider::class); + // parse test files up front, parent files are left for the rule to resolve -$classMethods = []; +// the rule finds the class of a method in the stmts of the current file, as in a real run +$classMethodsByFile = []; foreach ($testFilePaths as $testFilePath) { $stmts = $testingParser->parseFileToDecoratedNodes($testFilePath); - $classMethods = [...$classMethods, ...$betterNodeFinder->findInstanceOf($stmts, ClassMethod::class)]; + $file = new File($testFilePath, (string) file_get_contents($testFilePath)); + $file->hydrateStmtsAndTokens($stmts, $stmts, []); + $classMethodsByFile[] = [$file, $betterNodeFinder->findInstanceOf($stmts, ClassMethod::class)]; } $cpuSeconds = static function (): float { @@ -115,9 +123,15 @@ $cpuStart = $cpuSeconds(); $changedCount = 0; -foreach ($classMethods as $classMethod) { - if ($rector->refactor($classMethod) instanceof ClassMethod) { - ++$changedCount; +$classMethodCount = 0; +foreach ($classMethodsByFile as [$file, $classMethods]) { + $currentFileProvider->setFile($file); + + foreach ($classMethods as $classMethod) { + ++$classMethodCount; + if ($rector->refactor($classMethod) instanceof ClassMethod) { + ++$changedCount; + } } } @@ -127,8 +141,8 @@ array_map('unlink', glob($directory . '/*.php')); @rmdir($directory); -printf('test classes: %d, test methods: %d, changed: %d%s', count($testFilePaths), count($classMethods), $changedCount, PHP_EOL); -printf('CPU: %.4f s (%.3f ms/method)%s', $cpu, $cpu / count($classMethods) * 1000, PHP_EOL); +printf('test classes: %d, test methods: %d, changed: %d%s', count($testFilePaths), $classMethodCount, $changedCount, PHP_EOL); +printf('CPU: %.4f s (%.3f ms/method)%s', $cpu, $cpu / $classMethodCount * 1000, PHP_EOL); printf('wall: %.4f s%s', $wall, PHP_EOL); if ($cpu > MAX_CPU_SECONDS) { diff --git a/bench/does_not_perform_assertion_own_lifecycle_bench.php b/bench/does_not_perform_assertion_own_lifecycle_bench.php new file mode 100644 index 00000000..d3c8a08a --- /dev/null +++ b/bench/does_not_perform_assertion_own_lifecycle_bench.php @@ -0,0 +1,122 @@ +assertTrue(true);' : '$this->ready = true;'; + $methods = " protected function setUp(): void\n {\n parent::setUp();\n {$setUpBody}\n }\n\n"; + $methods .= " protected function tearDown(): void\n {\n \$this->ready = null;\n parent::tearDown();\n }\n\n"; + for ($testMethod = 0; $testMethod < TEST_METHODS; ++$testMethod) { + $methods .= " public function testSomething{$testMethod}(): void\n {\n \$value = {$testMethod};\n }\n\n"; + } + + $filePath = $directory . '/' . $className . '.php'; + file_put_contents( + $filePath, + "create(); +$rectorConfig->boot(); + +/** @var TestingParser $testingParser */ +$testingParser = $rectorConfig->make(TestingParser::class); + +/** @var BetterNodeFinder $betterNodeFinder */ +$betterNodeFinder = $rectorConfig->make(BetterNodeFinder::class); + +$rector = $rectorConfig->make(AddDoesNotPerformAssertionToNonAssertingTestRector::class); + +/** @var CurrentFileProvider $currentFileProvider */ +$currentFileProvider = $rectorConfig->make(CurrentFileProvider::class); + +// the rule finds the class of a method in the stmts of the current file, as in a real run +$classMethodsByFile = []; +foreach ($testFilePaths as $testFilePath) { + $stmts = $testingParser->parseFileToDecoratedNodes($testFilePath); + $file = new File($testFilePath, (string) file_get_contents($testFilePath)); + $file->hydrateStmtsAndTokens($stmts, $stmts, []); + $classMethodsByFile[] = [$file, $betterNodeFinder->findInstanceOf($stmts, ClassMethod::class)]; +} + +$cpuSeconds = static function (): float { + $usage = getrusage(); + return $usage['ru_utime.tv_sec'] + $usage['ru_utime.tv_usec'] / 1_000_000 + + $usage['ru_stime.tv_sec'] + $usage['ru_stime.tv_usec'] / 1_000_000; +}; + +$wallStart = microtime(true); +$cpuStart = $cpuSeconds(); + +$changedCount = 0; +$classMethodCount = 0; +foreach ($classMethodsByFile as [$file, $classMethods]) { + $currentFileProvider->setFile($file); + + foreach ($classMethods as $classMethod) { + ++$classMethodCount; + if ($rector->refactor($classMethod) instanceof ClassMethod) { + ++$changedCount; + } + } +} + +$cpu = $cpuSeconds() - $cpuStart; +$wall = microtime(true) - $wallStart; + +array_map('unlink', glob($directory . '/*.php')); +@rmdir($directory); + +printf('test classes: %d, test methods: %d, changed: %d%s', count($testFilePaths), $classMethodCount, $changedCount, PHP_EOL); +printf('CPU: %.4f s (%.3f ms/method)%s', $cpu, $cpu / $classMethodCount * 1000, PHP_EOL); +printf('wall: %.4f s%s', $wall, PHP_EOL); + +if ($cpu > MAX_CPU_SECONDS) { + printf('CPU %.4f s is over the %.1f s limit%s', $cpu, MAX_CPU_SECONDS, PHP_EOL); + exit(1); +} diff --git a/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/non_asserting_set_up.php.inc b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/non_asserting_set_up.php.inc new file mode 100644 index 00000000..4273e653 --- /dev/null +++ b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/non_asserting_set_up.php.inc @@ -0,0 +1,42 @@ +value = 1; + } + + public function testSomething() + { + $value = 5; + } +} + +?> +----- +value = 1; + } + + #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] + public function testSomething() + { + $value = 5; + } +} + +?> diff --git a/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_after_annotation.php.inc b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_after_annotation.php.inc new file mode 100644 index 00000000..6219c981 --- /dev/null +++ b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_after_annotation.php.inc @@ -0,0 +1,21 @@ +assertTrue(true); + } + + public function testSomething() + { + $value = 5; + } +} diff --git a/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_aliased_before_attribute.php.inc b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_aliased_before_attribute.php.inc new file mode 100644 index 00000000..9876bdea --- /dev/null +++ b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_aliased_before_attribute.php.inc @@ -0,0 +1,20 @@ +assertTrue(true); + } + + public function testSomething() + { + $value = 1; + } +} diff --git a/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_before_attribute.php.inc b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_before_attribute.php.inc new file mode 100644 index 00000000..2f549b94 --- /dev/null +++ b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_before_attribute.php.inc @@ -0,0 +1,20 @@ +assertTrue(true); + } + + public function testSomething() + { + $value = 5; + } +} diff --git a/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_hook_after_anonymous_class.php.inc b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_hook_after_anonymous_class.php.inc new file mode 100644 index 00000000..f56730e7 --- /dev/null +++ b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_hook_after_anonymous_class.php.inc @@ -0,0 +1,26 @@ +assertNotNull($object); + } + + public function testSecond() + { + $value = 1; + } + + protected function tearDown(): void + { + $this->assertTrue(true); + } +} diff --git a/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_own_post_conditions.php.inc b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_own_post_conditions.php.inc new file mode 100644 index 00000000..fe6a9772 --- /dev/null +++ b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_own_post_conditions.php.inc @@ -0,0 +1,18 @@ +assertTrue(true); + } + + public function testSomething() + { + $value = 5; + } +} diff --git a/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_set_up.php.inc b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_set_up.php.inc new file mode 100644 index 00000000..f2e13004 --- /dev/null +++ b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_set_up.php.inc @@ -0,0 +1,18 @@ +assertTrue(true); + } + + public function testSomething() + { + $value = 5; + } +} diff --git a/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_set_up_helper.php.inc b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_set_up_helper.php.inc new file mode 100644 index 00000000..db04b80e --- /dev/null +++ b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_asserting_set_up_helper.php.inc @@ -0,0 +1,24 @@ +init(); + } + + private function init(): void + { + self::assertSame(1, 1); + } + + public function testSomething() + { + $value = 1; + } +} diff --git a/rules/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector.php b/rules/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector.php index 52e64bf3..f3308a9a 100644 --- a/rules/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector.php +++ b/rules/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector.php @@ -9,6 +9,7 @@ use PhpParser\Node\AttributeGroup; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Name\FullyQualified; +use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; use PhpParser\Node\Stmt\Nop; @@ -20,9 +21,11 @@ use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use Rector\Comments\NodeDocBlock\DocBlockUpdater; use Rector\Php80\NodeAnalyzer\PhpAttributeAnalyzer; +use Rector\PhpParser\Node\BetterNodeFinder; use Rector\PHPUnit\Enum\PHPUnitAttribute; use Rector\PHPUnit\Enum\PHPUnitClassName; use Rector\PHPUnit\NodeAnalyzer\AssertCallAnalyzer; +use Rector\PHPUnit\NodeAnalyzer\LifecycleMethodAssertAnalyzer; use Rector\PHPUnit\NodeAnalyzer\MockedVariableAnalyzer; use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer; use Rector\Rector\AbstractRector; @@ -57,6 +60,8 @@ public function __construct( private readonly PhpDocInfoFactory $phpDocInfoFactory, private readonly ReflectionResolver $reflectionResolver, private readonly ReflectionProvider $reflectionProvider, + private readonly LifecycleMethodAssertAnalyzer $lifecycleMethodAssertAnalyzer, + private readonly BetterNodeFinder $betterNodeFinder, ) { } @@ -169,6 +174,12 @@ private function shouldSkipClassMethod(ClassMethod $classMethod): bool return true; } + // assertions in lifecycle methods count toward every test of the class + $class = $this->resolveCurrentClass($classMethod); + if ($class instanceof Class_ && $this->lifecycleMethodAssertAnalyzer->hasAssertingLifecycleMethod($class)) { + return true; + } + return $this->mockedVariableAnalyzer->containsMockAsUsedVariable($classMethod); } @@ -235,6 +246,17 @@ private function isInAbstractClass(ClassMethod $classMethod): bool return $classReflection->isAbstract(); } + private function resolveCurrentClass(ClassMethod $classMethod): ?Class_ + { + $class = $this->betterNodeFinder->findFirst( + $this->getFile() + ->getNewStmts(), + fn (Node $node): bool => $node instanceof Class_ && in_array($classMethod, $node->getMethods(), true) + ); + + return $class instanceof Class_ ? $class : null; + } + private function isInTwigIntegrationTestCase(ClassMethod $classMethod): bool { $classReflection = $this->reflectionResolver->resolveClassReflection($classMethod); diff --git a/src/Enum/PHPUnitAttribute.php b/src/Enum/PHPUnitAttribute.php index cca04295..7a93fece 100644 --- a/src/Enum/PHPUnitAttribute.php +++ b/src/Enum/PHPUnitAttribute.php @@ -33,4 +33,12 @@ final class PHPUnitAttribute public const string ALLOW_MOCK_OBJECTS_WITHOUT_EXPECTATIONS = 'PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations'; public const string DATA_PROVIDER = 'PHPUnit\Framework\Attributes\DataProvider'; + + public const string BEFORE = 'PHPUnit\Framework\Attributes\Before'; + + public const string AFTER = 'PHPUnit\Framework\Attributes\After'; + + public const string PRE_CONDITION = 'PHPUnit\Framework\Attributes\PreCondition'; + + public const string POST_CONDITION = 'PHPUnit\Framework\Attributes\PostCondition'; } diff --git a/src/NodeAnalyzer/LifecycleMethodAssertAnalyzer.php b/src/NodeAnalyzer/LifecycleMethodAssertAnalyzer.php new file mode 100644 index 00000000..5e501e50 --- /dev/null +++ b/src/NodeAnalyzer/LifecycleMethodAssertAnalyzer.php @@ -0,0 +1,95 @@ + + */ + private WeakMap $assertingByClass; + + public function __construct( + private AssertCallAnalyzer $assertCallAnalyzer, + private PhpAttributeAnalyzer $phpAttributeAnalyzer, + private PhpDocInfoFactory $phpDocInfoFactory, + private NodeNameResolver $nodeNameResolver, + ) { + $this->assertingByClass = new WeakMap(); + } + + public function hasAssertingLifecycleMethod(Class_ $class): bool + { + // every test method of the class shares the result + return $this->assertingByClass[$class] ??= $this->resolveHasAssertingLifecycleMethod($class); + } + + private function resolveHasAssertingLifecycleMethod(Class_ $class): bool + { + foreach ($class->getMethods() as $classMethod) { + if (! $this->isLifecycleMethod($classMethod)) { + continue; + } + + $this->assertCallAnalyzer->resetNesting(); + if ($this->assertCallAnalyzer->containsAssertCall($classMethod)) { + return true; + } + } + + return false; + } + + private function isLifecycleMethod(ClassMethod $classMethod): bool + { + if ($this->nodeNameResolver->isNames($classMethod->name, self::HOOK_METHOD_NAMES)) { + return true; + } + + if ($classMethod->attrGroups !== [] + && $this->phpAttributeAnalyzer->hasPhpAttributes($classMethod, self::HOOK_ATTRIBUTES)) { + return true; + } + + if (! $classMethod->getDocComment() instanceof Doc) { + return false; + } + + return $this->phpDocInfoFactory->createFromNodeOrEmpty($classMethod) + ->hasByNames(self::HOOK_ANNOTATIONS); + } +} From a328667b16907481bd5a2e328dee193ca253fd90 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sat, 14 Nov 2026 18:10:21 +0100 Subject: [PATCH 2/2] Add lifecycle fixtures already covered by own class hooks and parent:: calls --- ...et_up_override_without_parent_call.php.inc | 56 +++++++++++++++ .../skip_post_conditions_parent_call.php.inc | 18 +++++ ...g_parent_of_non_asserting_ancestor.php.inc | 68 +++++++++++++++++++ ...stractClassWithAssertingPostConditions.php | 15 ++++ 4 files changed, 157 insertions(+) create mode 100644 rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/set_up_override_without_parent_call.php.inc create mode 100644 rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_post_conditions_parent_call.php.inc create mode 100644 rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/trait_set_up_calling_parent_of_non_asserting_ancestor.php.inc create mode 100644 rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Source/AbstractClassWithAssertingPostConditions.php diff --git a/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/set_up_override_without_parent_call.php.inc b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/set_up_override_without_parent_call.php.inc new file mode 100644 index 00000000..123ec276 --- /dev/null +++ b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/set_up_override_without_parent_call.php.inc @@ -0,0 +1,56 @@ +assertTrue(true); + } +} + +final class ShadowChild extends ShadowBase +{ + protected function setUp(): void + { + $value = 1; + } + + public function testSomething() + { + $value = 1; + } +} +?> +----- +assertTrue(true); + } +} + +final class ShadowChild extends ShadowBase +{ + protected function setUp(): void + { + $value = 1; + } + + #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] + public function testSomething() + { + $value = 1; + } +} +?> diff --git a/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_post_conditions_parent_call.php.inc b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_post_conditions_parent_call.php.inc new file mode 100644 index 00000000..0c0a5f47 --- /dev/null +++ b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Fixture/skip_post_conditions_parent_call.php.inc @@ -0,0 +1,18 @@ + +----- + diff --git a/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Source/AbstractClassWithAssertingPostConditions.php b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Source/AbstractClassWithAssertingPostConditions.php new file mode 100644 index 00000000..9cb7da7a --- /dev/null +++ b/rules-tests/PHPUnit60/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector/Source/AbstractClassWithAssertingPostConditions.php @@ -0,0 +1,15 @@ +assertTrue(true); + } +}