diff --git a/src/Moka/Exception/MockNotServedException.php b/src/Moka/Exception/MockNotServedException.php deleted file mode 100644 index 220b2d3..0000000 --- a/src/Moka/Exception/MockNotServedException.php +++ /dev/null @@ -1,12 +0,0 @@ -className = [ - FooTestClass::class, - BarTestClass::class - ][random_int(0, 1)]; - $this->namesWithValues = [ '$property' => mt_rand(), '$public' => mt_rand(), @@ -47,11 +38,10 @@ protected function setUp() 'isTrue' => (bool)random_int(0, 1), 'getInt' => mt_rand(), 'withArgument' => mt_rand(), - 'throwException' => new \Exception('' . mt_rand()) + 'throwException' => new \Exception((string)mt_rand()) ]; - $this->mock = $this->strategy->build($this->className); - + $this->mock = $this->strategy->build($this->getRandomFQCN()); $this->strategy->decorate($this->mock, $this->namesWithValues); } @@ -60,43 +50,36 @@ final public function testGetMockTypeSuccess() $this->assertInternalType('string', $this->strategy->getMockType()); } - final public function testBuildClassSuccess() - { - $this->assertInstanceOf($this->strategy->getMockType(), $this->mock); - } - - final public function testBuildInterfaceSuccess() + /** + * @dataProvider fqcnProvider + */ + final public function testBuildAndGet(bool $required, string $fqcnType, string ...$fqcns) { - $mock = $this->strategy->build(TestInterface::class); - - $this->assertInstanceOf($this->strategy->getMockType(), $mock); + if (true === $required) { + $this->buildAndGet(...$fqcns); + } else { + $this->tryBuildAndGet($fqcnType, ...$fqcns); + } } - final public function testBuildAbstractClassSuccess() + /** + * @requires PHP 7.1 + */ + public function testBuildWithPHP71Class() { - $mock = $this->strategy->build(AbstractTestClass::class); - - $this->assertInstanceOf($this->strategy->getMockType(), $mock); + $this->checkMock( + $this->strategy->build(PHP71TestClass::class) + ); } - final public function testDecorateFailure() + final public function testDecorateFakeMockFailure() { $this->expectException(InvalidArgumentException::class); - $this->strategy->decorate(new \stdClass(), $this->namesWithValues); - } - - final public function testDecorateWrongTypeHintFailure() - { - $this->strategy->decorate($this->mock, [ - 'getSelf' => mt_rand() - ]); - - $this->expectException(\TypeError::class); - $this->strategy->get($this->mock)->getSelf(); + $this->strategy->decorate(new FooTestClass(), $this->namesWithValues); } - final public function testDecorateWithPropertyFailure() + final public function testDecorateWithPropertySuccess() { $this->assertEquals( $this->namesWithValues['$property'], @@ -117,7 +100,7 @@ final public function testDecorateWithProtectedPropertyFailure() $this->expectException(\Error::class); $this->strategy->decorate($this->mock, [ - '$protected' => 1138 + '$protected' => mt_rand() ]); } @@ -129,65 +112,158 @@ final public function testDecorateWithPrivatePropertySuccess() ); } - final public function testDecorateWithMethodSingleCallSuccess() + final public function testDecorateWithWrongTypeHintFailure() + { + $this->strategy->decorate($this->mock, [ + 'getSelf' => mt_rand() + ]); + + $this->expectException(\TypeError::class); + $this->strategy->get($this->mock)->getSelf(); + } + + final public function testDecorateWithNonexistentMethod() { - $this->assertSame($this->namesWithValues['isTrue'], $this->strategy->get($this->mock)->isTrue()); + try { + $value = mt_rand(); + $this->strategy->decorate($this->mock, [ + 'nonexistentMethod' => $value + ]); + + $this->assertSame( + $value, + $this->strategy->get($this->mock)->nonexistentMethod() + ); + } catch (\Throwable $e) { + $this->markFeatureUnsupported('stubbing a nonexistent method'); + } + } + + final public function testCallUnstubbedMethod() + { + try { + $mock = $this->strategy->build(FooTestClass::class); + + $this->assertInstanceOf( + TestInterface::class, + $this->strategy->get($mock)->getSelf() + ); + } catch (\Throwable $e) { + $this->markFeatureUnsupported('calling an unstubbed method'); + } + } + + final public function testSingleMethodCallSuccess() + { + $this->assertSame( + $this->namesWithValues['isTrue'], + $this->strategy->get($this->mock)->isTrue() + ); $this->expectException(\Exception::class); $this->expectExceptionMessage($this->namesWithValues['throwException']->getMessage()); $this->strategy->get($this->mock)->throwException(); } - final public function testDecorateWithMethodMultipleCallsSuccess() + final public function testMultipleMethodCallsSuccess() { - $this->assertSame($this->namesWithValues['getInt'], $this->strategy->get($this->mock)->getInt()); - $this->assertSame($this->namesWithValues['getInt'], $this->strategy->get($this->mock)->getInt()); + $this->assertSame( + $this->namesWithValues['getInt'], + $this->strategy->get($this->mock)->getInt() + ); + + $this->assertSame( + $this->namesWithValues['getInt'], + $this->strategy->get($this->mock)->getInt() + ); } - final public function testDecorateWithMethodOverriddenCallsFailure() + final public function testOverrideMethodStubFailure() { $this->strategy->decorate($this->mock, [ 'getInt' => mt_rand(), 'throwException' => mt_rand() ]); - $this->assertSame($this->namesWithValues['getInt'], $this->strategy->get($this->mock)->getInt()); - $this->assertSame($this->namesWithValues['getInt'], $this->strategy->get($this->mock)->getInt()); + $this->assertSame( + $this->namesWithValues['getInt'], + $this->strategy->get($this->mock)->getInt() + ); + + $this->assertSame( + $this->namesWithValues['getInt'], + $this->strategy->get($this->mock)->getInt() + ); $this->expectException(\Exception::class); $this->expectExceptionMessage($this->namesWithValues['throwException']->getMessage()); $this->strategy->get($this->mock)->throwException(); } - final public function testDecorateWithMethodCallWithArgumentSuccess() + final public function testCallMethodWithArgumentSuccess() { - $this->assertSame($this->namesWithValues['withArgument'], $this->strategy->get($this->mock)->withArgument(mt_rand())); + $this->assertSame( + $this->namesWithValues['withArgument'], + $this->strategy->get($this->mock)->withArgument(mt_rand()) + ); } - final public function testDecorateWithMethodCallWithMissingArgumentFailure() + final public function testCallMethodWithoutArgumentFailure() { $this->expectException(\Error::class); $this->strategy->get($this->mock)->withArgument(); } - final public function testDecorateWithMethodCallWithWrongArgumentFailure() + final public function testCallMethodWithWrongArgumentFailure() { $this->expectException(\TypeError::class); $this->strategy->get($this->mock)->withArgument('string'); } - final public function testGetSuccess() + final public function testGetFakeMockFailure() { - $this->assertInstanceOf($this->className, $this->strategy->get($this->mock)); + $this->expectException(InvalidArgumentException::class); + + $this->strategy->get(new \stdClass()); } - final public function testGetFailure() + final public function fqcnProvider(): array { - $this->expectException(InvalidArgumentException::class); + $required = [ + ['an interface', TestInterface::class], + ['an abstract class', AbstractTestClass::class], + ['a class', $this->getRandomFQCN()] + ]; - $this->strategy->get(new \stdClass()); + $optional = [ + ['an empty FQCN', self::FQCN_EMPTY], + ['an invalid FQCN', self::FQCN_INVALID], + ['a nonexistent FQCN', $this->getNonexistentFQCN()], + ['multiple interfaces', FooTestInterface::class, BarTestInterface::class], + ['class and interface', FooTestClass::class, BarTestInterface::class], + ['multiple classes', FooTestClass::class, BarTestClass::class], + ['multiple nonexistent FQCNs', $this->getNonexistentFQCN(), $this->getNonexistentFQCN()] + ]; + + $data = array_merge( + array_map(function (array $set) { + array_unshift($set, $required = true); + return $set; + }, $required), + array_map(function (array $set) { + array_unshift($set, $required = false); + return $set; + }, $optional) + ); + + return array_reduce($data, function (array $data, array $set) { + $key = preg_replace('/^an? +/', '', $set[1]); + $data[$key] = $set; + + return $data; + }, []); } final protected function setStrategy(MockingStrategyInterface $strategy) @@ -195,8 +271,80 @@ final protected function setStrategy(MockingStrategyInterface $strategy) $this->strategy = $strategy; } - final protected function getRandomFQCN() + final protected function getRandomFQCN(): string + { + return [ + FooTestClass::class, + BarTestClass::class + ][random_int(0, 1)]; + } + + final protected function getNonexistentFQCN(): string + { + return sprintf( + self::FQCN_NONEXISTENT_TEMPLATE, + mt_rand() + ); + } + + final protected function checkMock($mock) + { + $this->assertInstanceOf($this->strategy->getMockType(), $mock); + } + + final protected function markFeatureUnsupported(string $feature) + { + $this->markTestSkipped( + sprintf( + 'Strategy "%s" doesn\'t support %s', + get_class($this->strategy), + $feature + ) + ); + } + + private function buildAndGet(string ...$fqcns) + { + $this->checkMock( + $mock = $this->strategy->build(implode(', ', $fqcns)) + ); + + $object = $this->strategy->get($mock); + foreach ($fqcns as $fqcn) { + $this->assertInstanceOf($fqcn, $object); + } + } + + private function tryBuildAndGet(string $fqcnType, string ...$fqcns) { - return 'foo_' . mt_rand(); + try { + $this->checkMock( + $mock = $this->strategy->build(implode(', ', $fqcns)) + ); + } catch (MockNotCreatedException $e) { + $this->markFeatureUnsupported( + sprintf( + 'building with %s: %s', + $fqcnType, + $e->getMessage() + ) + ); + + return; + } + + $object = $this->strategy->get($mock); + foreach ($fqcns as $fqcn) { + if (!is_a($object, $fqcn)) { + $this->markFeatureUnsupported( + sprintf( + 'getting a valid mock from %s', + $fqcnType + ) + ); + + return; + } + } } } diff --git a/src/Moka/Tests/PHP71TestClass.php b/src/Moka/Tests/PHP71TestClass.php new file mode 100644 index 0000000..761bd48 --- /dev/null +++ b/src/Moka/Tests/PHP71TestClass.php @@ -0,0 +1,16 @@ +assertRegExp('/: *\? *Tests\\\NewTestClass/', $code); + $this->assertRegExp( + sprintf( + '/: *\? *%s/', + addslashes(PHP71TestClass::class) + ), + $code + ); } } diff --git a/tests/MokaTest.php b/tests/MokaTest.php index c53c4fd..41bff47 100644 --- a/tests/MokaTest.php +++ b/tests/MokaTest.php @@ -6,6 +6,7 @@ use Moka\Exception\NotImplementedException; use Moka\Moka; use Moka\Proxy\ProxyInterface; +use Moka\Tests\FooTestClass; use PHPUnit\Framework\TestCase; use Prophecy\Argument\Token\AnyValuesToken; diff --git a/tests/NewTestClass.php b/tests/NewTestClass.php deleted file mode 100644 index 3635ca5..0000000 --- a/tests/NewTestClass.php +++ /dev/null @@ -1,12 +0,0 @@ -setStrategy(new MockeryMockingStrategy()); } - - public function testBuildEmptyFQCNFailure() - { - $this->expectException(MockNotCreatedException::class); - - $this->strategy->build(''); - } - - public function testBuildParseFailure() - { - $this->expectException(MockNotCreatedException::class); - - $this->strategy->build('foo bar'); - } - - public function testBuildFakeFQCNSuccess() - { - $mock = $this->strategy->build($this->getRandomFQCN()); - - $this->assertInstanceOf($this->strategy->getMockType(), $mock); - } - - public function testBuildMultipleFQCNSuccess() - { - $mock = $this->strategy->build(FooTestClass::class . ', ' . BarTestClass::class); - - $this->assertInstanceOf($this->strategy->getMockType(), $mock); - } - - public function testBuildMultipleFakeFQCNFailure() - { - $this->expectException(MockNotCreatedException::class); - - $this->strategy->build($this->getRandomFQCN() . ', ' . $this->getRandomFQCN()); - } - - public function testDecorateFakeMethodSuccess() - { - $this->strategy->decorate($this->mock, [ - 'fakeMethod' => true - ]); - - $this->assertSame(true, $this->strategy->get($this->mock)->fakeMethod()); - } - - public function testCallMissingMethodFailure() - { - $mock = $this->strategy->build(FooTestClass::class); - - $this->expectException(\Throwable::class); - $this->strategy->get($mock)->getSelf(); - } - - public function testGetFakeFQCNSuccess() - { - $fqcn = $this->getRandomFQCN(); - $mock = $this->strategy->build($fqcn); - - $this->assertTrue(is_a($this->strategy->get($mock), $fqcn)); - } - - public function testGetMultipleClassInterfaceSuccess() - { - $mock = $this->strategy->build(FooTestClass::class . ', ' . TestInterface::class); - - $this->assertTrue(is_a($this->strategy->get($mock), FooTestClass::class)); - $this->assertTrue(is_a($this->strategy->get($mock), TestInterface::class)); - } - - public function testGetMultipleFQCNPartialSuccess() - { - $mock = $this->strategy->build(FooTestClass::class . ', ' . BarTestClass::class); - - $this->assertFalse(is_a($this->strategy->get($mock), FooTestClass::class)); - $this->assertTrue(is_a($this->strategy->get($mock), BarTestClass::class)); - } } diff --git a/tests/Plugin/PHPUnit/PHPUnitMockingStrategyTest.php b/tests/Plugin/PHPUnit/PHPUnitMockingStrategyTest.php index 3238ec8..36b144c 100644 --- a/tests/Plugin/PHPUnit/PHPUnitMockingStrategyTest.php +++ b/tests/Plugin/PHPUnit/PHPUnitMockingStrategyTest.php @@ -3,12 +3,8 @@ namespace Tests\Plugin\PHPUnit; -use Moka\Exception\MockNotCreatedException; use Moka\Plugin\PHPUnit\PHPUnitMockingStrategy; use Moka\Tests\MokaMockingStrategyTestCase; -use Tests\BarTestClass; -use Tests\FooTestClass; -use Tests\TestInterface; class PHPUnitMockingStrategyTest extends MokaMockingStrategyTestCase { @@ -18,56 +14,4 @@ public function __construct($name = null, array $data = [], $dataName = '') $this->setStrategy(new PHPUnitMockingStrategy()); } - - public function testBuildEmptyFQCNFailure() - { - $this->expectException(MockNotCreatedException::class); - - $this->strategy->build(''); - } - - public function testBuildParseFailure() - { - $this->expectException(MockNotCreatedException::class); - - $this->strategy->build('foo bar'); - } - - public function testBuildFakeFQCNSuccess() - { - $mock = $this->strategy->build($this->getRandomFQCN()); - - $this->assertInstanceOf($this->strategy->getMockType(), $mock); - } - - public function testBuildMultipleFQCNFailure() - { - $this->expectException(MockNotCreatedException::class); - - $this->strategy->build(FooTestClass::class . ', ' . BarTestClass::class); - } - - public function testDecorateFakeMethodFailure() - { - $this->expectException(\Exception::class); - - $this->strategy->decorate($this->mock, [ - 'fakeMethod' => true - ]); - } - - public function testCallMissingMethodSuccess() - { - $mock = $this->strategy->build(FooTestClass::class); - - $this->assertInstanceOf(TestInterface::class, $this->strategy->get($mock)->getSelf()); - } - - public function testGetFakeFQCNSuccess() - { - $fqcn = $this->getRandomFQCN(); - $mock = $this->strategy->build($fqcn); - - $this->assertTrue(is_a($this->strategy->get($mock), $fqcn)); - } } diff --git a/tests/Plugin/Phake/PhakeMockingStrategyTest.php b/tests/Plugin/Phake/PhakeMockingStrategyTest.php index 5917d73..46db477 100644 --- a/tests/Plugin/Phake/PhakeMockingStrategyTest.php +++ b/tests/Plugin/Phake/PhakeMockingStrategyTest.php @@ -3,12 +3,8 @@ namespace Tests\Plugin\Phake; -use Moka\Exception\MockNotCreatedException; use Moka\Plugin\Phake\PhakeMockingStrategy; use Moka\Tests\MokaMockingStrategyTestCase; -use Tests\BarTestClass; -use Tests\FooTestClass; -use Tests\TestInterface; class PhakeMockingStrategyTest extends MokaMockingStrategyTestCase { @@ -19,56 +15,11 @@ public function __construct($name = null, array $data = [], $dataName = '') $this->setStrategy(new PhakeMockingStrategy()); } - public function testBuildEmptyFQCNFailure() + /** + * @requires PHP 7.1 + */ + public function testBuildWithPHP71Class() { - $this->expectException(MockNotCreatedException::class); - - $this->strategy->build(''); - } - - public function testBuildParseFailure() - { - $this->expectException(MockNotCreatedException::class); - - $this->strategy->build('foo bar'); - } - - public function testBuildFakeFQCNFailure() - { - $this->expectException(MockNotCreatedException::class); - - $this->strategy->build($this->getRandomFQCN()); - } - - public function testBuildMultipleFQCNFailure() - { - $this->expectException(MockNotCreatedException::class); - - $this->strategy->build(FooTestClass::class . ', ' . BarTestClass::class); - } - - public function testDecorateFakeMethodFailure() - { - $this->strategy->decorate($this->mock, [ - 'fakeMethod' => true - ]); - - $this->expectException(\Error::class); - $this->strategy->get($this->mock)->fakeMethod(); - } - - public function testCallMissingMethodFailure() - { - $mock = $this->strategy->build(FooTestClass::class); - - $this->expectException(\Throwable::class); - $this->strategy->get($mock)->getSelf(); - } - - public function testGetMultipleFQCNFailure() - { - $this->expectException(\Exception::class); - - $this->strategy->build(FooTestClass::class . ', ' . TestInterface::class); + $this->markFeatureUnsupported('PHP 7.1 features'); } } diff --git a/tests/Plugin/Prophecy/ProphecyMockingStrategyTest.php b/tests/Plugin/Prophecy/ProphecyMockingStrategyTest.php index 8095f13..3b29f95 100644 --- a/tests/Plugin/Prophecy/ProphecyMockingStrategyTest.php +++ b/tests/Plugin/Prophecy/ProphecyMockingStrategyTest.php @@ -5,13 +5,12 @@ use Moka\Exception\MockNotCreatedException; use Moka\Plugin\Prophecy\ProphecyMockingStrategy; +use Moka\Tests\FooTestClass; use Moka\Tests\MokaMockingStrategyTestCase; use Prophecy\Doubler\Doubler; use Prophecy\Doubler\LazyDouble; use Prophecy\Prophecy\MethodProphecy; use Prophecy\Prophecy\ObjectProphecy; -use Tests\FooTestClass; -use Tests\TestInterface; class ProphecyMockingStrategyTest extends MokaMockingStrategyTestCase { @@ -22,44 +21,6 @@ public function __construct($name = null, array $data = [], $dataName = '') $this->setStrategy(new ProphecyMockingStrategy()); } - public function testBuildEmptyFQCNSuccess() - { - $mock = $this->strategy->build(''); - - $this->assertInstanceOf($this->strategy->getMockType(), $mock); - } - - public function testBuildFakeFQCNSuccess() - { - $mock = $this->strategy->build($this->getRandomFQCN()); - - $this->assertInstanceOf($this->strategy->getMockType(), $mock); - } - - public function testBuildMultipleFQCNSuccess() - { - $mock = $this->strategy->build($this->getRandomFQCN() . ', ' . $this->getRandomFQCN()); - - $this->assertInstanceOf($this->strategy->getMockType(), $mock); - } - - public function testDecorateFakeMethodFailure() - { - $this->expectException(\Exception::class); - - $this->strategy->decorate($this->mock, [ - 'fakeMethod' => true - ]); - } - - public function testCallMissingMethodFailure() - { - $mock = $this->strategy->build(FooTestClass::class); - - $this->expectException(\Throwable::class); - $this->strategy->get($mock)->getSelf(); - } - public function testGetCustomMockFailure() { $this->expectException(MockNotCreatedException::class); @@ -67,32 +28,6 @@ public function testGetCustomMockFailure() $this->strategy->get(new ObjectProphecy(new LazyDouble(new Doubler()))); } - public function testGetFakeFQCNFailure() - { - $fqcn = $this->getRandomFQCN(); - $mock = $this->strategy->build($fqcn); - - $this->assertFalse(is_a($this->strategy->get($mock), $fqcn)); - } - - public function testGetMultipleClassInterfaceFailure() - { - $mock = $this->strategy->build(FooTestClass::class . ', ' . TestInterface::class); - - $this->assertFalse(is_a($this->strategy->get($mock), FooTestClass::class)); - $this->assertFalse(is_a($this->strategy->get($mock), TestInterface::class)); - } - - public function testGetMultipleFakeFQCNFailure() - { - $fqcn1 = $this->getRandomFQCN(); - $fqcn2 = $this->getRandomFQCN(); - $mock = $this->strategy->build($fqcn1 . ', ' . $fqcn2); - - $this->assertFalse(is_a($this->strategy->get($mock), $fqcn1)); - $this->assertFalse(is_a($this->strategy->get($mock), $fqcn2)); - } - public function testCallObjectProphecy() { $mock = $this->strategy->build(FooTestClass::class); diff --git a/tests/Proxy/ProxyTraitTest.php b/tests/Proxy/ProxyTraitTest.php index dfb08de..d8b1651 100644 --- a/tests/Proxy/ProxyTraitTest.php +++ b/tests/Proxy/ProxyTraitTest.php @@ -5,9 +5,9 @@ use Moka\Proxy\ProxyInterface; use Moka\Strategy\MockingStrategyInterface; +use Moka\Tests\FooTestClass; use PHPUnit\Framework\TestCase; use PHPUnit_Framework_MockObject_MockObject as MockObject; -use Tests\FooTestClass; class ProxyTraitTest extends TestCase { diff --git a/tests/Strategy/IncompleteMockingStrategy.php b/tests/Strategy/IncompleteMockingStrategy.php index 2fc6a03..a250a1b 100644 --- a/tests/Strategy/IncompleteMockingStrategy.php +++ b/tests/Strategy/IncompleteMockingStrategy.php @@ -14,6 +14,7 @@ class IncompleteMockingStrategy extends AbstractMockingStrategy protected function doBuild(string $fqcn) { + throw new \Exception(); } protected function doDecorateWithMethod($mock, MethodStub $stub) diff --git a/tests/Strategy/MockingStrategyTest.php b/tests/Strategy/MockingStrategyTest.php index 4832cf2..8180c8b 100644 --- a/tests/Strategy/MockingStrategyTest.php +++ b/tests/Strategy/MockingStrategyTest.php @@ -4,6 +4,7 @@ namespace Tests\Strategy; use Moka\Exception\MissingDependencyException; +use Moka\Exception\MockNotCreatedException; use Moka\Exception\NotImplementedException; use PHPUnit\Framework\TestCase; @@ -24,12 +25,19 @@ public function testGetMockTypeFailure() $strategy->getMockType(); } + public function testBuildFailure() + { + $strategy = new BareMockingStrategy(); + + $this->expectException(MockNotCreatedException::class); + $strategy->build(\stdClass::class); + } + public function testCallFailure() { $strategy = new BareMockingStrategy(); $this->expectException(\Error::class); - $strategy->call(new \stdClass(), 'foo'); } }