Skip to content

Commit e403c02

Browse files
authored
Merge pull request #6 from tweakers/interface-proxy
Interface proxy
2 parents 28836f0 + 0024bff commit e403c02

File tree

3 files changed

+90
-19
lines changed

3 files changed

+90
-19
lines changed

composer.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
}
1414
},
1515
"require": {
16-
"php": "^7.2|^8.0",
17-
"ocramius/proxy-manager": "^2.11"
16+
"php": "^8.0",
17+
"friendsofphp/proxy-manager-lts": "^1.0.16"
1818
},
1919
"require-dev": {
20-
"phpunit/phpunit": "^9.5"
20+
"phpunit/phpunit": "^10.2"
2121
},
2222
"license": "MIT",
2323
"authors": [

src/MockableService/MockableServiceProxyFactory.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,36 @@ public function createServiceProxy(object $original): MockableService
2929
return $proxy;
3030
}
3131

32+
/**
33+
* Similar to createServiceProxy, but with the class/interface to proxy explicitly specified.
34+
*
35+
* This allows proxying of instances of final implementations of the given interface.
36+
*
37+
* @param object $original The service to use as original.
38+
* @param string $className The class (interface) to proxy.
39+
*
40+
* @return MockableService
41+
*/
42+
public function createInterfaceServiceProxy(object $original, string $className): MockableService
43+
{
44+
// Body copied from parent::createProxy
45+
46+
/** @var MockableService $proxy */
47+
$proxyClassName = $this->generateProxy($className);
48+
49+
/**
50+
* We ignore type checks here, since `staticProxyConstructor` is not interfaced (by design)
51+
*
52+
* @psalm-suppress MixedMethodCall
53+
* @psalm-suppress MixedReturnStatement
54+
*/
55+
$proxy = $proxyClassName::staticProxyConstructor($original, [], []);
56+
57+
$proxy->setOriginalService($original);
58+
59+
return $proxy;
60+
}
61+
3262
/** {@inheritdoc} */
3363
protected function getGenerator(): ProxyGeneratorInterface
3464
{

test/MockableService/MockableServiceProxyFactoryTest.php

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,48 +16,89 @@ class MockableServiceProxyFactoryTest extends TestCase
1616
/** @var FakeService */
1717
private $alternative;
1818

19-
/** @var MockableService|FakeService $proxy */
20-
private $proxy;
21-
2219
protected function setUp(): void
2320
{
2421
parent::setUp();
2522

2623
$this->original = new FakeService('orig');
2724
$this->alternative = new FakeService('mock');
28-
29-
$factory = new MockableServiceProxyFactory();
30-
31-
$this->proxy = $factory->createServiceProxy($this->original);
3225
}
3326

3427
/** @test */
3528
public function it_should_generate_a_mockable_service_proxy(): void
3629
{
37-
$this->assertInstanceOf(MockableService::class, $this->proxy);
38-
$this->assertInstanceOf(FakeService::class, $this->proxy);
30+
$factory = new MockableServiceProxyFactory();
31+
/** @var FakeService&MockableService $proxy */
32+
$proxy = $factory->createServiceProxy($this->original);
3933

40-
$this->assertEquals($this->original->getValue(), $this->proxy->getValue());
34+
$this->assertInstanceOf(MockableService::class, $proxy);
35+
$this->assertInstanceOf(FakeService::class, $proxy);
36+
37+
$this->assertEquals($this->original->getValue(), $proxy->getValue());
4138
}
4239

4340
/** @test */
4441
public function it_should_generate_a_working_set_alternative(): void
4542
{
46-
$this->proxy->setAlternativeService($this->alternative);
47-
$this->assertEquals($this->alternative->getValue(), $this->proxy->getValue());
43+
$factory = new MockableServiceProxyFactory();
44+
/** @var FakeService&MockableService $proxy */
45+
$proxy = $factory->createServiceProxy($this->original);
46+
47+
$proxy->setAlternativeService($this->alternative);
48+
$this->assertEquals($this->alternative->getValue(), $proxy->getValue());
4849
}
4950

5051
/** @test */
5152
public function it_should_generate_a_working_reset(): void
5253
{
53-
$this->proxy->setAlternativeService($this->alternative);
54-
$this->proxy->restoreOriginalService();
54+
$factory = new MockableServiceProxyFactory();
55+
/** @var FakeService&MockableService $proxy */
56+
$proxy = $factory->createServiceProxy($this->original);
57+
58+
$proxy->setAlternativeService($this->alternative);
59+
$proxy->restoreOriginalService();
60+
61+
$this->assertEquals($this->original->getValue(), $proxy->getValue());
62+
}
63+
64+
/** @test */
65+
public function it_should_generate_a_mockable_service_proxy_via_an_interface(): void
66+
{
67+
$original = new FinalFakeService('value');
68+
69+
$factory = new MockableServiceProxyFactory();
70+
/** @var FinalFakeService&MockableService $proxy */
71+
$proxy = $factory->createInterfaceServiceProxy($original, TestInterface::class);
72+
73+
$this->assertInstanceOf(MockableService::class, $proxy);
74+
$this->assertInstanceOf(TestInterface::class, $proxy);
75+
76+
$this->assertEquals($original->getValue(), $proxy->getValue());
77+
}
78+
}
79+
80+
interface TestInterface
81+
{
82+
public function getValue(): string;
83+
}
84+
85+
class FakeService implements TestInterface
86+
{
87+
/** @var string */
88+
private $value;
89+
90+
public function __construct(string $value)
91+
{
92+
$this->value = $value;
93+
}
5594

56-
$this->assertEquals($this->original->getValue(), $this->proxy->getValue());
95+
public function getValue(): string
96+
{
97+
return $this->value;
5798
}
5899
}
59100

60-
class FakeService
101+
final class FinalFakeService implements TestInterface
61102
{
62103
/** @var string */
63104
private $value;

0 commit comments

Comments
 (0)