From 4adde21094dd608e7071f45cc505d7fbae672919 Mon Sep 17 00:00:00 2001 From: Kevin Pfeifer Date: Mon, 2 Sep 2024 19:11:55 +0200 Subject: [PATCH] unmockify the testsuite for Routing & View --- .../Middleware/RoutingMiddlewareTest.php | 70 ++++++--- tests/TestCase/Routing/Route/RouteTest.php | 16 +-- tests/TestCase/Routing/RouterTest.php | 17 +-- .../TestSuite/Fixture/FixtureHelperTest.php | 133 +++++++++++++----- tests/TestCase/View/Helper/FormHelperTest.php | 66 ++++----- tests/TestCase/View/HelperTest.php | 20 ++- 6 files changed, 202 insertions(+), 120 deletions(-) diff --git a/tests/TestCase/Routing/Middleware/RoutingMiddlewareTest.php b/tests/TestCase/Routing/Middleware/RoutingMiddlewareTest.php index 2d167bffc80..792b2a0ef33 100644 --- a/tests/TestCase/Routing/Middleware/RoutingMiddlewareTest.php +++ b/tests/TestCase/Routing/Middleware/RoutingMiddlewareTest.php @@ -17,7 +17,6 @@ namespace Cake\Test\TestCase\Routing\Middleware; use Cake\Core\Configure; -use Cake\Core\HttpApplicationInterface; use Cake\Http\ServerRequestFactory; use Cake\Routing\Exception\MissingRouteException; use Cake\Routing\Middleware\RoutingMiddleware; @@ -26,8 +25,11 @@ use Cake\Routing\Router; use Cake\Routing\RoutingApplicationInterface; use Cake\TestSuite\TestCase; +use Closure; use Laminas\Diactoros\Response; use PHPUnit\Framework\Attributes\DataProvider; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; use TestApp\Application; use TestApp\Http\TestRequestHandler; use TestApp\Middleware\DumbMiddleware; @@ -194,15 +196,28 @@ public function testRoutesHookCallsPluginHook(): void Router::reload(); $request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/app/articles']); - $app = $this->getMockBuilder(Application::class) - ->onlyMethods(['pluginRoutes']) - ->setConstructorArgs([CONFIG]) - ->getMock(); - $app->expects($this->once()) - ->method('pluginRoutes') - ->with($this->isInstanceOf(RouteBuilder::class)); + $app = new class (CONFIG) extends Application { + public function pluginRoutes(RouteBuilder $routes): RouteBuilder + { + $routes->connect('/app/articles', ['controller' => 'Articles', 'action' => 'index']); + + return $routes; + } + }; $middleware = new RoutingMiddleware($app); - $middleware->process($request, new TestRequestHandler()); + $middleware->process($request, new TestRequestHandler(function ($req) { + $expected = [ + 'controller' => 'Articles', + 'action' => 'index', + 'plugin' => null, + 'pass' => [], + '_ext' => null, + '_matchedRoute' => '/app/articles', + ]; + $this->assertEquals($expected, $req->getAttribute('params')); + + return new Response(); + })); } /** @@ -446,8 +461,11 @@ public static function scopedMiddlewareUrlProvider(): array */ public function testAppWithoutContainerApplicationInterface(): void { - /** @var \Cake\Core\HttpApplicationInterface|\PHPUnit\Framework\MockObject\MockObject $app */ - $app = $this->createMock(RoutingApplicationInterface::class); + $app = new class implements RoutingApplicationInterface { + public function routes(RouteBuilder $routes): void + { + } + }; $this->builder->scope('/', function (RouteBuilder $routes): void { $routes->connect('/testpath', ['controller' => 'Articles', 'action' => 'index']); }); @@ -483,19 +501,27 @@ public function testAppWithContainerApplicationInterface(): void * * @param callable|null $handleCallback Callback for "handle" method. */ - protected function app($handleCallback = null): HttpApplicationInterface + protected function app(?callable $handleCallback = null): Application { - $mock = $this->createMock(Application::class); - $mock->method('routes') - ->willReturnCallback(function (RouteBuilder $routes) { - return $routes; - }); + $app = new class (CONFIG) extends Application { + public ?Closure $handleCallback; + + public function routes(RouteBuilder $routes): void + { + } + + public function handle(ServerRequestInterface $request): ResponseInterface + { + if ($this->handleCallback) { + return ($this->handleCallback)($request); + } + + return parent::handle($request); // TODO: Change the autogenerated stub + } + }; - if ($handleCallback) { - $mock->method('handle') - ->willReturnCallback($handleCallback); - } + $app->handleCallback = $handleCallback; - return $mock; + return $app; } } diff --git a/tests/TestCase/Routing/Route/RouteTest.php b/tests/TestCase/Routing/Route/RouteTest.php index 8af6ce4080c..a4d8e41c614 100644 --- a/tests/TestCase/Routing/Route/RouteTest.php +++ b/tests/TestCase/Routing/Route/RouteTest.php @@ -1038,16 +1038,12 @@ public function testQueryStringGeneration(): void */ public function testParseRequestDelegates(): void { - /** @var \Cake\Routing\Route\Route|\PHPUnit\Framework\MockObject\MockObject $route */ - $route = $this->getMockBuilder(Route::class) - ->onlyMethods(['parse']) - ->setConstructorArgs(['/forward', ['controller' => 'Articles', 'action' => 'index']]) - ->getMock(); - - $route->expects($this->once()) - ->method('parse') - ->with('/forward', 'GET') - ->willReturn(['works!']); + $route = new class ('/forward', ['controller' => 'Articles', 'action' => 'index']) extends Route { + public function parse(string $url, string $method): ?array + { + return ['works!']; + } + }; $request = new ServerRequest([ 'environment' => [ diff --git a/tests/TestCase/Routing/RouterTest.php b/tests/TestCase/Routing/RouterTest.php index f5d895e031a..0940becb7ee 100644 --- a/tests/TestCase/Routing/RouterTest.php +++ b/tests/TestCase/Routing/RouterTest.php @@ -2989,20 +2989,17 @@ public function testGetRequest(): void */ public function testUrlFullUrlReturnFromRoute(): void { - $url = 'http://example.com/posts/view/1'; - - $route = $this->getMockBuilder(Route::class) - ->onlyMethods(['match']) - ->setConstructorArgs(['/{controller}/{action}/*']) - ->getMock(); - $route->expects($this->any()) - ->method('match') - ->willReturn($url); + $route = new class ('/{controller}/{action}/*') extends Route { + public function match(array $url, array $context = []): ?string + { + return 'http://example.com/posts/view/1'; + } + }; Router::createRouteBuilder('/')->connect($route); $result = Router::url(['controller' => 'Posts', 'action' => 'view', 1]); - $this->assertSame($url, $result); + $this->assertSame('http://example.com/posts/view/1', $result); } /** diff --git a/tests/TestCase/TestSuite/Fixture/FixtureHelperTest.php b/tests/TestCase/TestSuite/Fixture/FixtureHelperTest.php index 2aa790606e0..86f53df35a3 100644 --- a/tests/TestCase/TestSuite/Fixture/FixtureHelperTest.php +++ b/tests/TestCase/TestSuite/Fixture/FixtureHelperTest.php @@ -17,6 +17,8 @@ namespace Cake\Test\TestCase\TestSuite; use Cake\Core\Exception\CakeException; +use Cake\Database\Connection; +use Cake\Datasource\ConnectionInterface; use Cake\Datasource\ConnectionManager; use Cake\Test\Fixture\ArticlesFixture; use Cake\TestSuite\Fixture\FixtureHelper; @@ -106,15 +108,26 @@ public function testLoadDulicateFixtures(): void */ public function testPerConnection(): void { - $fixture1 = $this->createMock(TestFixture::class); - $fixture1->expects($this->once()) - ->method('connection') - ->willReturn('test1'); + $fixture1 = new class extends TestFixture { + public function connection(): string + { + return 'test1'; + } - $fixture2 = $this->createMock(TestFixture::class); - $fixture2->expects($this->once()) - ->method('connection') - ->willReturn('test2'); + protected function _schemaFromReflection(): void + { + } + }; + $fixture2 = new class extends TestFixture { + public function connection(): string + { + return 'test2'; + } + + protected function _schemaFromReflection(): void + { + } + }; ConnectionManager::alias('test', 'test1'); ConnectionManager::alias('test', 'test2'); @@ -152,23 +165,45 @@ public function testInsertFixtures(): void */ public function testInsertFixturesException(): void { - $fixture = $this->getMockBuilder(TestFixture::class)->getMock(); - $fixture->expects($this->once()) - ->method('connection') - ->willReturn('test'); - $fixture->expects($this->once()) - ->method('insert') - ->will($this->throwException(new PDOException('Missing key'))); - - $helper = $this->getMockBuilder(FixtureHelper::class) - ->onlyMethods(['sortByConstraint']) - ->getMock(); - $helper->expects($this->any()) - ->method('sortByConstraint') - ->willReturn([$fixture]); + $fixture = new class extends TestFixture { + public function connection(): string + { + return 'test'; + } + + protected function _schemaFromReflection(): void + { + } + + public function insert(ConnectionInterface $connection): bool + { + throw new PDOException('Missing key'); + } + }; + + $helper = new class extends FixtureHelper { + public function sortByConstraint(Connection $connection, array $fixtures): array + { + return [new class extends TestFixture { + public function connection(): string + { + return 'test'; + } + + protected function _schemaFromReflection(): void + { + } + + public function insert(ConnectionInterface $connection): bool + { + throw new PDOException('Missing key'); + } + }]; + } + }; $this->expectException(CakeException::class); - $this->expectExceptionMessage('Unable to insert rows for table ``'); + $this->expectExceptionMessage('Unable to insert rows for table `'); $helper->insert([$fixture]); } @@ -197,23 +232,45 @@ public function testTruncateFixtures(): void */ public function testTruncateFixturesException(): void { - $fixture = $this->getMockBuilder(TestFixture::class)->getMock(); - $fixture->expects($this->once()) - ->method('connection') - ->willReturn('test'); - $fixture->expects($this->once()) - ->method('truncate') - ->will($this->throwException(new PDOException('Missing key'))); - - $helper = $this->getMockBuilder(FixtureHelper::class) - ->onlyMethods(['sortByConstraint']) - ->getMock(); - $helper->expects($this->any()) - ->method('sortByConstraint') - ->willReturn([$fixture]); + $fixture = new class extends TestFixture { + public function connection(): string + { + return 'test'; + } + + protected function _schemaFromReflection(): void + { + } + + public function truncate(ConnectionInterface $connection): bool + { + throw new PDOException('Missing key'); + } + }; + + $helper = new class extends FixtureHelper { + public function sortByConstraint(Connection $connection, array $fixtures): array + { + return [new class extends TestFixture { + public function connection(): string + { + return 'test'; + } + + protected function _schemaFromReflection(): void + { + } + + public function truncate(ConnectionInterface $connection): bool + { + throw new PDOException('Missing key'); + } + }]; + } + }; $this->expectException(CakeException::class); - $this->expectExceptionMessage('Unable to truncate table ``'); + $this->expectExceptionMessage('Unable to truncate table `'); $helper->truncate([$fixture]); } } diff --git a/tests/TestCase/View/Helper/FormHelperTest.php b/tests/TestCase/View/Helper/FormHelperTest.php index 022fa9b205b..05c46af90b0 100644 --- a/tests/TestCase/View/Helper/FormHelperTest.php +++ b/tests/TestCase/View/Helper/FormHelperTest.php @@ -217,16 +217,20 @@ public function testConstructWithGroupedInputTypes(): void */ public function testAddWidgetAndRenderWidget(): void { - $data = [ - 'val' => 1, - ]; - $mock = $this->getMockBuilder(WidgetInterface::class)->getMock(); - $this->Form->addWidget('test', $mock); - $mock->expects($this->once()) - ->method('render') - ->with($data) - ->willReturn('HTML'); - $result = $this->Form->widget('test', $data); + $widget = new class implements WidgetInterface + { + public function render(array $data, ContextInterface $context): string + { + return 'HTML'; + } + + public function secureFields(array $data): array + { + return ['val']; + } + }; + $this->Form->addWidget('test', $widget); + $result = $this->Form->widget('test', ['val' => 1]); $this->assertSame('HTML', $result); } @@ -240,25 +244,21 @@ public function testOrderForRenderingWidgetAndFetchingSecureFields(): void 'unlockedFields' => [], ])); - $data = [ - 'val' => 1, - 'name' => 'test', - ]; - $mock = $this->getMockBuilder(WidgetInterface::class)->getMock(); - $this->Form->addWidget('test', $mock); - - $mock->expects($this->once()) - ->method('render') - ->with($data) - ->willReturn('HTML'); - - $mock->expects($this->once()) - ->method('secureFields') - ->with($data) - ->willReturn(['test']); + $widget = new class implements WidgetInterface + { + public function render(array $data, ContextInterface $context): string + { + return 'HTML'; + } + public function secureFields(array $data): array + { + return ['test']; + } + }; + $this->Form->addWidget('test', $widget); $this->Form->create(); - $result = $this->Form->widget('test', $data + ['secure' => true]); + $result = $this->Form->widget('test', ['val' => 1, 'name' => 'test', 'secure' => true]); $this->assertSame('HTML', $result); } @@ -288,7 +288,7 @@ public function testRenderingWidgetWithEmptyName(): void public function testAddContextProvider(): void { $context = 'My data'; - $stub = $this->getMockBuilder(ContextInterface::class)->getMock(); + $stub = new StubContext(); $this->Form->addContextProvider('test', function ($request, $data) use ($context, $stub) { $this->assertInstanceOf(ServerRequest::class, $request); $this->assertSame($context, $data['entity']); @@ -306,7 +306,7 @@ public function testAddContextProvider(): void public function testAddContextProviderReplace(): void { $entity = new Article(); - $stub = $this->getMockBuilder(ContextInterface::class)->getMock(); + $stub = new StubContext(); $this->Form->addContextProvider('orm', function ($request, $data) use ($stub) { return $stub; }); @@ -321,7 +321,7 @@ public function testAddContextProviderReplace(): void public function testAddContextProviderAdd(): void { $entity = new Article(); - $stub = $this->getMockBuilder(ContextInterface::class)->getMock(); + $stub = new StubContext(); $this->Form->addContextProvider('newshiny', function ($request, $data) use ($stub) { if ($data['entity'] instanceof Entity) { return $stub; @@ -8239,9 +8239,9 @@ public function testContext(): void $result = $this->Form->context(); $this->assertInstanceOf(ContextInterface::class, $result); - $mock = $this->getMockBuilder(ContextInterface::class)->getMock(); - $this->assertSame($mock, $this->Form->context($mock)); - $this->assertSame($mock, $this->Form->context()); + $stub = new StubContext(); + $this->assertSame($stub, $this->Form->context($stub)); + $this->assertSame($stub, $this->Form->context()); } /** diff --git a/tests/TestCase/View/HelperTest.php b/tests/TestCase/View/HelperTest.php index cdbb5accbbf..f07a842d9d3 100644 --- a/tests/TestCase/View/HelperTest.php +++ b/tests/TestCase/View/HelperTest.php @@ -19,11 +19,14 @@ namespace Cake\Test\TestCase\View; use Cake\Core\Configure; +use Cake\Event\EventListenerInterface; use Cake\Event\EventManager; use Cake\Routing\Router; use Cake\TestSuite\TestCase; +use Cake\View\Helper; use Cake\View\Helper\HtmlHelper; use Cake\View\View; +use Exception; use TestApp\View\Helper\TestHelper; use TestPlugin\View\Helper\OtherHelperHelper; @@ -94,14 +97,17 @@ public function testLazyLoadingHelpers(): void */ public function testThatHelperHelpersAreNotAttached(): void { - $events = $this->getMockBuilder(EventManager::class)->getMock(); - $this->View->setEventManager($events); + $eventsManager = new class extends EventManager + { + public function on(string|EventListenerInterface $eventKey, callable|array $options = [], ?callable $callable = null) + { + throw new Exception('Should not be called'); + } + }; + $this->View->setEventManager($eventsManager); - $events->expects($this->never()) - ->method('on'); - - $Helper = new TestHelper($this->View); - $Helper->OtherHelper; + $helper = new TestHelper($this->View); + $this->assertInstanceOf(Helper::class, $helper->OtherHelper); } /**