Skip to content

Commit 4265cb6

Browse files
committed
[phpunit 12] Add PropertyCreateMockToCreateStubRector
1 parent 9f5f19d commit 4265cb6

File tree

11 files changed

+372
-1
lines changed

11 files changed

+372
-1
lines changed

config/sets/phpunit-code-quality.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
use Rector\PHPUnit\CodeQuality\Rector\MethodCall\WithCallbackIdenticalToStandaloneAssertsRector;
5252
use Rector\PHPUnit\CodeQuality\Rector\StmtsAwareInterface\DeclareStrictTypesTestsRector;
5353
use Rector\PHPUnit\PHPUnit120\Rector\CallLike\CreateStubOverCreateMockArgRector;
54+
use Rector\PHPUnit\PHPUnit120\Rector\Class_\PropertyCreateMockToCreateStubRector;
5455
use Rector\PHPUnit\PHPUnit120\Rector\ClassMethod\ExpressionCreateMockToCreateStubRector;
5556
use Rector\PHPUnit\PHPUnit60\Rector\MethodCall\GetMockBuilderGetMockToCreateMockRector;
5657
use Rector\PHPUnit\PHPUnit90\Rector\MethodCall\ReplaceAtMethodWithDesiredMatcherRector;
@@ -130,6 +131,7 @@
130131
// stub over mock
131132
CreateStubOverCreateMockArgRector::class,
132133
ExpressionCreateMockToCreateStubRector::class,
134+
PropertyCreateMockToCreateStubRector::class,
133135

134136
// @test first, enable later
135137
// \Rector\PHPUnit\CodeQuality\Rector\Expression\ConfiguredMockEntityToSetterObjectRector::class,

config/sets/phpunit120.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Rector\Config\RectorConfig;
66
use Rector\PHPUnit\PHPUnit120\Rector\CallLike\CreateStubOverCreateMockArgRector;
77
use Rector\PHPUnit\PHPUnit120\Rector\Class_\AssertIsTypeMethodCallRector;
8+
use Rector\PHPUnit\PHPUnit120\Rector\Class_\PropertyCreateMockToCreateStubRector;
89
use Rector\PHPUnit\PHPUnit120\Rector\Class_\RemoveOverrideFinalConstructTestCaseRector;
910
use Rector\PHPUnit\PHPUnit120\Rector\ClassMethod\ExpressionCreateMockToCreateStubRector;
1011

@@ -16,6 +17,7 @@
1617
// stubs over mocks
1718
CreateStubOverCreateMockArgRector::class,
1819
ExpressionCreateMockToCreateStubRector::class,
20+
PropertyCreateMockToCreateStubRector::class,
1921

2022
// experimental, from PHPUnit 12.5.2
2123
// @see https://github.com/sebastianbergmann/phpunit/commit/24c208d6a340c3071f28a9b5cce02b9377adfd43
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\PHPUnit120\Rector\Class_\PropertyCreateMockToCreateStubRector\Fixture;
4+
5+
use PHPUnit\Framework\TestCase;
6+
7+
final class SomeTest extends TestCase
8+
{
9+
private \PHPUnit\Framework\MockObject\MockObject $someMock;
10+
11+
protected function setUp(): void
12+
{
13+
$this->someMock = $this->createMock(\stdClass::class);
14+
}
15+
16+
public function testThis()
17+
{
18+
$this->assertSame('...', $this->someMock);
19+
}
20+
21+
public function testThat()
22+
{
23+
$this->assertSame('...', $this->someMock);
24+
}
25+
}
26+
27+
?>
28+
-----
29+
<?php
30+
31+
namespace Rector\PHPUnit\Tests\PHPUnit120\Rector\Class_\PropertyCreateMockToCreateStubRector\Fixture;
32+
33+
use PHPUnit\Framework\TestCase;
34+
35+
final class SomeTest extends TestCase
36+
{
37+
private \PHPUnit\Framework\MockObject\Stub $someMock;
38+
39+
protected function setUp(): void
40+
{
41+
$this->someMock = $this->createStub(\stdClass::class);
42+
}
43+
44+
public function testThis()
45+
{
46+
$this->assertSame('...', $this->someMock);
47+
}
48+
49+
public function testThat()
50+
{
51+
$this->assertSame('...', $this->someMock);
52+
}
53+
}
54+
55+
?>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\PHPUnit120\Rector\Class_\PropertyCreateMockToCreateStubRector\Fixture;
4+
5+
use PHPUnit\Framework\TestCase;
6+
7+
final class SkipPropertyUse extends TestCase
8+
{
9+
private \PHPUnit\Framework\MockObject\MockObject $someMock;
10+
11+
protected function setUp(): void
12+
{
13+
$this->someMock = $this->createMock(\stdClass::class);
14+
}
15+
16+
public function testThis()
17+
{
18+
$this->someMock->expects($this->atLeastOnce())->method('something');
19+
$this->assertSame('...', $this->someMock);
20+
}
21+
22+
public function testThat()
23+
{
24+
$this->assertSame('...', $this->someMock);
25+
}
26+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\PHPUnit\Tests\PHPUnit120\Rector\Class_\PropertyCreateMockToCreateStubRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class PropertyCreateMockToCreateStubRectorTest extends AbstractRectorTestCase
12+
{
13+
#[DataProvider('provideData')]
14+
public function test(string $filePath): void
15+
{
16+
$this->doTestFile($filePath);
17+
}
18+
19+
public static function provideData(): Iterator
20+
{
21+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
22+
}
23+
24+
public function provideConfigFilePath(): string
25+
{
26+
return __DIR__ . '/config/configured_rule.php';
27+
}
28+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\PHPUnit120\Rector\Class_\PropertyCreateMockToCreateStubRector\Source;
4+
5+
final class ClassWithDependency
6+
{
7+
public function __construct(
8+
private $dependency,
9+
) {
10+
}
11+
12+
public function getDependency()
13+
{
14+
return $this->dependency;
15+
}
16+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\PHPUnit\PHPUnit120\Rector\Class_\PropertyCreateMockToCreateStubRector;
7+
8+
return RectorConfig::configure()
9+
->withRules(rules: [PropertyCreateMockToCreateStubRector::class]);

rules/CodeQuality/NodeAnalyser/MockObjectExprDetector.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
use PhpParser\Node\Expr;
88
use PhpParser\Node\Expr\MethodCall;
9+
use PhpParser\Node\Expr\PropertyFetch;
910
use PhpParser\Node\Expr\Variable;
11+
use PhpParser\Node\Stmt\Class_;
1012
use PhpParser\Node\Stmt\ClassMethod;
1113
use Rector\NodeNameResolver\NodeNameResolver;
1214
use Rector\PhpParser\Node\BetterNodeFinder;
@@ -58,4 +60,25 @@ public function isUsedForMocking(Expr $expr, ClassMethod $classMethod): bool
5860

5961
return false;
6062
}
63+
64+
public function isPropertyUsedForMocking(Class_ $class, string $propertyName): bool
65+
{
66+
// find out, how many are used in call likes as args
67+
/** @var array<Expr\MethodCall> $methodCalls */
68+
$methodCalls = $this->betterNodeFinder->findInstancesOfScoped($class->getMethods(), [MethodCall::class]);
69+
70+
foreach ($methodCalls as $methodCall) {
71+
if (! $methodCall->var instanceof PropertyFetch) {
72+
continue;
73+
}
74+
75+
$propertyFetch = $methodCall->var;
76+
if ($this->nodeNameResolver->isName($propertyFetch->name, $propertyName)) {
77+
// variable is being called on, most like mocking, lets skip
78+
return true;
79+
}
80+
}
81+
82+
return false;
83+
}
6184
}

rules/CodeQuality/NodeAnalyser/MockObjectPropertyDetector.php

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,23 @@
44

55
namespace Rector\PHPUnit\CodeQuality\NodeAnalyser;
66

7+
use PhpParser\Node\Expr\Assign;
8+
use PhpParser\Node\Expr\MethodCall;
9+
use PhpParser\Node\Expr\PropertyFetch;
710
use PhpParser\Node\Name\FullyQualified;
11+
use PhpParser\Node\Stmt\ClassMethod;
12+
use PhpParser\Node\Stmt\Expression;
813
use PhpParser\Node\Stmt\Property;
14+
use Rector\NodeNameResolver\NodeNameResolver;
915
use Rector\PHPUnit\Enum\PHPUnitClassName;
1016

11-
final class MockObjectPropertyDetector
17+
final readonly class MockObjectPropertyDetector
1218
{
19+
public function __construct(
20+
private NodeNameResolver $nodeNameResolver
21+
) {
22+
}
23+
1324
public function detect(Property $property): bool
1425
{
1526
if (! $property->type instanceof FullyQualified) {
@@ -18,4 +29,48 @@ public function detect(Property $property): bool
1829

1930
return $property->type->toString() === PHPUnitClassName::MOCK_OBJECT;
2031
}
32+
33+
/**
34+
* @return array<string, MethodCall>
35+
*/
36+
public function collectFromClassMethod(ClassMethod $classMethod): array
37+
{
38+
$propertyNamesToCreateMockMethodCalls = [];
39+
40+
foreach ((array) $classMethod->stmts as $stmt) {
41+
if (! $stmt instanceof Expression) {
42+
continue;
43+
}
44+
45+
if (! $stmt->expr instanceof Assign) {
46+
continue;
47+
}
48+
49+
$assign = $stmt->expr;
50+
51+
if (! $assign->var instanceof PropertyFetch) {
52+
continue;
53+
}
54+
55+
if (! $assign->expr instanceof MethodCall) {
56+
continue;
57+
}
58+
59+
$methodCall = $assign->expr;
60+
if (! $this->nodeNameResolver->isName($methodCall->name, 'createMock')) {
61+
continue;
62+
}
63+
64+
$propertyFetch = $assign->var;
65+
$propertyName = $this->nodeNameResolver->getName($propertyFetch->name);
66+
67+
if (! is_string($propertyName)) {
68+
continue;
69+
}
70+
71+
$propertyNamesToCreateMockMethodCalls[$propertyName] = $methodCall;
72+
}
73+
74+
return $propertyNamesToCreateMockMethodCalls;
75+
}
2176
}

0 commit comments

Comments
 (0)