Skip to content

Commit c32ea12

Browse files
committed
ContainerDoubleTrait: Allow configuring mising services
Also it is possible to get the ObjectProphecy object instead of the revealed double
1 parent 9e8923a commit c32ea12

2 files changed

Lines changed: 92 additions & 15 deletions

File tree

src/TestCase/ContainerDoubleTrait.php

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111

1212
namespace Cross\TestUtils\TestCase;
1313

14+
use Cross\TestUtils\Exception\InvalidUsageException;
15+
use Prophecy\Prophecy\ObjectProphecy;
16+
1417
/**
15-
* Creates a service manager double with configured services.
18+
* Creates a service manager prophecy or double with configured services.
1619
*
1720
* @method \Prophecy\Prophecy\ObjectProphecy prophesize(string $classOrInterface)
1821
*
@@ -21,7 +24,7 @@
2124
trait ContainerDoubleTrait
2225
{
2326
/**
24-
* Prohesizes a container interface double.
27+
* Prohesizes a container interface.
2528
*
2629
* Pass in services as iterable:
2730
* <pre>
@@ -36,21 +39,30 @@ trait ContainerDoubleTrait
3639
* ]
3740
* </pre>
3841
*
42+
* Passing the boolean value 'false' as service will cause the following:
43+
* - Calling has(service) will return false.
44+
* - Calling get(service) will throw an exception.
45+
*
3946
* @param iterable $services
4047
*
41-
* @return object
48+
* @return ObjectProphecy
4249
*/
43-
public function createContainerDouble(iterable $services = []): object
50+
public function createContainerProphecy(iterable $services = []): ObjectProphecy
4451
{
45-
/** @noinspection PhpUndefinedClassInspection */
46-
/** @noinspection PhpUndefinedNamespaceInspection */
52+
if (!interface_exists(\Psr\Container\ContainerInterface::class)) {
53+
throw InvalidUsageException::fromTrait(
54+
__TRAIT__,
55+
get_class($this),
56+
'Cannot create container double. Interface %s does not exist.',
57+
\Psr\Container\ContainerInterface::class
58+
);
59+
}
60+
4761
$container = $this->prophesize(\Psr\Container\ContainerInterface::class);
4862

4963
foreach ($services as $name => $spec) {
5064
if (!is_array($spec)) {
51-
$container->get($name)->willReturn($spec);
52-
$container->has($name)->willReturn(true);
53-
continue;
65+
$spec = ['service' => $spec];
5466
}
5567

5668
$countGet = $spec['count_get'] ?? $spec[1] ?? 0;
@@ -59,20 +71,39 @@ public function createContainerDouble(iterable $services = []): object
5971

6072
/** @var \Prophecy\Prophecy\MethodProphecy $method */
6173
$method = $container->get($name);
62-
$method->willReturn($service);
74+
75+
if (false === $service) {
76+
$ex = $this->prophesize(\Psr\Container\NotFoundExceptionInterface::class)->reveal();
77+
$method->willThrow($ex);
78+
} else {
79+
$method->willReturn($service);
80+
}
6381

6482
if ($countGet) {
6583
$method->shouldBeCalledTimes($countGet);
6684
}
6785

6886
$method = $container->has($name);
69-
$method->willReturn(true);
87+
$method->willReturn(false !== $service);
7088

7189
if ($countHas) {
7290
$method->shouldBeCalledTimes($countHas);
7391
}
7492
}
7593

76-
return $container->reveal();
94+
return $container;
95+
}
96+
97+
/**
98+
* Creates a container interface double.
99+
*
100+
* @param iterable $services The services the container should provide
101+
* see {@link createContainerProphecy()}
102+
*
103+
* @return object The revealed container double
104+
*/
105+
public function createContainerDouble(iterable $services = []): object
106+
{
107+
return $this->createContainerProphecy($services)->reveal();
77108
}
78109
}

test/TestUtilsTest/TestCase/ContainerDoubleTraitTest.php

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@
1111

1212
namespace Cross\TestUtilsTest\TestCase;
1313

14+
use Cross\TestUtils\Exception\InvalidUsageException;
15+
1416
use Cross\TestUtils\TestCase\ContainerDoubleTrait;
1517

18+
use Prophecy\Argument;
19+
20+
use phpmock\prophecy\PHPProphet;
21+
1622
/**
1723
* Tests for \Cross\TestUtils\TestCase\ContainerDoubleTrait
1824
*
@@ -91,6 +97,18 @@ public function servicesProvider()
9197
'reveal' => [[]]
9298
]
9399
],
100+
[
101+
[
102+
'name' => false,
103+
],
104+
[
105+
'get' => [['name']],
106+
'willThrow' => [['ExceptionMock']],
107+
'reveal' => [[]],
108+
'has' => [['name']],
109+
'willReturn' => [[false]],
110+
],
111+
],
94112
];
95113
}
96114

@@ -102,13 +120,15 @@ public function servicesProvider()
102120
*/
103121
public function testCreatesContainerDouble(array $services, array $expect)
104122
{
123+
$scope = $this;
105124
$target = new class
106125
{
107126
use ContainerDoubleTrait;
108127

109128
public function prophesize($class)
110129
{
111-
return new class($class)
130+
131+
return new class($class) extends \Prophecy\Prophecy\ObjectProphecy
112132
{
113133
public $name;
114134
public $calls = [];
@@ -124,15 +144,41 @@ public function __call($method, $args)
124144

125145
return $this;
126146
}
147+
148+
public function reveal()
149+
{
150+
if (\Psr\Container\NotFoundExceptionInterface::class == $this->name) {
151+
return 'ExceptionMock';
152+
}
153+
154+
$this->calls['reveal'][] = [];
155+
156+
return $this;
157+
}
127158
};
128159
}
129160
};
130161

131162
$actual = $target->createContainerDouble($services);
132163

133-
/** @noinspection PhpUndefinedNamespaceInspection */
134-
/** @noinspection PhpUndefinedClassInspection */
135164
static::assertEquals(\Psr\Container\ContainerInterface::class, $actual->name);
136165
static::assertEquals($expect, $actual->calls);
137166
}
167+
168+
public function testThrowsExceptionIfInterfaceIsNotDefined()
169+
{
170+
171+
$func = (new PHPProphet)->prophesize('Cross\TestUtils\TestCase');
172+
$func->interface_exists(Argument::any())->willReturn(false);
173+
$func->reveal();
174+
175+
$this->expectException(InvalidUsageException::class);
176+
177+
$target = new class {
178+
use ContainerDoubleTrait;
179+
};
180+
181+
$target->createContainerProphecy();
182+
183+
}
138184
}

0 commit comments

Comments
 (0)