Browse Source

Raise error when no mocks are found

When the HttpClient cannot find a mocked response it should raise an
error. This makes it simpler to detect mistakes in mock setup code, and
make tests more explicit.
Mark Story 4 years ago
parent
commit
21ffbdf2f4

+ 11 - 6
src/Http/Client/Adapter/Mock.php

@@ -16,6 +16,7 @@ declare(strict_types=1);
 namespace Cake\Http\Client\Adapter;
 
 use Cake\Http\Client\AdapterInterface;
+use Cake\Http\Client\Exception\MissingResponseException;
 use Cake\Http\Client\Response;
 use Closure;
 use InvalidArgumentException;
@@ -26,6 +27,8 @@ use Psr\Http\Message\RequestInterface;
  *
  * This adapter is not intended for production use. Instead
  * it is the backend used by `Client::addMockResponse()`
+ *
+ * @internal
  */
 class Mock implements AdapterInterface
 {
@@ -71,11 +74,14 @@ class Mock implements AdapterInterface
     public function send(RequestInterface $request, array $options): array
     {
         $found = null;
+        $method = $request->getMethod();
+        $requestUri = (string)$request->getUri();
+
         foreach ($this->responses as $index => $mock) {
-            if ($request->getMethod() !== $mock['request']->getMethod()) {
+            if ($method !== $mock['request']->getMethod()) {
                 continue;
             }
-            if (!$this->urlMatches($request, $mock['request'])) {
+            if (!$this->urlMatches($requestUri, $mock['request'])) {
                 continue;
             }
             if (isset($mock['options']['match'])) {
@@ -100,19 +106,18 @@ class Mock implements AdapterInterface
             return [$mock['response']];
         }
 
-        return [];
+        throw new MissingResponseException($method, $requestUri);
     }
 
     /**
      * Check if the request URI matches the mock URI.
      *
-     * @param \Psr\Http\Message\RequestInterface $request The request being sent.
+     * @param string $requestUri The request being sent.
      * @param \Psr\Http\Message\RequestInterface $mock The request being mocked.
      * @return bool
      */
-    protected function urlMatches(RequestInterface $request, RequestInterface $mock): bool
+    protected function urlMatches(string $requestUri, RequestInterface $mock): bool
     {
-        $requestUri = (string)$request->getUri();
         $mockUri = (string)$mock->getUri();
         if ($requestUri === $mockUri) {
             return true;

+ 36 - 0
src/Http/Client/Exception/MissingResponseException.php

@@ -0,0 +1,36 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+ * @link          https://cakephp.org CakePHP(tm) Project
+ * @since         3.0.0
+ * @license       https://opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\Http\Client\Exception;
+
+use RuntimeException;
+
+/**
+ * Used to indicate that a request did not have a matching mock response.
+ */
+class MissingResponseException extends RuntimeException
+{
+    /**
+     * Constructor
+     *
+     * @param string $method The HTTP method used.
+     * @param string $url The request URL.
+     */
+    public function __construct(string $method, string $url)
+    {
+        $message = "Unable to find a mocked response for {$method} to {$url}.";
+        parent::__construct($message);
+    }
+}

+ 8 - 21
tests/TestCase/Http/ClientTest.php

@@ -17,6 +17,7 @@ namespace Cake\Test\TestCase\Http;
 
 use Cake\Http\Client;
 use Cake\Http\Client\Adapter\Stream;
+use Cake\Http\Client\Exception\MissingResponseException;
 use Cake\Http\Client\Request;
 use Cake\Http\Client\Response;
 use Cake\Http\Cookie\Cookie;
@@ -1056,16 +1057,9 @@ class ClientTest extends TestCase
         $stub = new Response(['HTTP/1.0 200'], 'hello world');
         Client::addMockResponse('POST', 'http://example.com/path', $stub);
 
-        $mock = $this->getMockBuilder(Stream::class)
-            ->onlyMethods(['send'])
-            ->getMock();
-        $mock->expects($this->once())
-            ->method('send')
-            ->will($this->throwException(new InvalidArgumentException('No match')));
-
-        $client = new Client(['adapter' => $mock]);
-        $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('No match');
+        $client = new Client();
+        $this->expectException(MissingResponseException::class);
+        $this->expectExceptionMessage('Unable to find a mock');
 
         $client->get('http://example.com/path');
     }
@@ -1131,21 +1125,14 @@ class ClientTest extends TestCase
     {
         $stub = new Response(['HTTP/1.0 200'], 'hello world');
         Client::addMockResponse('POST', 'http://example.com/path', $stub, [
-            'match' => function ($request) {
+            'match' => function () {
                 return false;
             },
         ]);
 
-        $mock = $this->getMockBuilder(Stream::class)
-            ->onlyMethods(['send'])
-            ->getMock();
-        $mock->expects($this->once())
-            ->method('send')
-            ->will($this->throwException(new InvalidArgumentException('No match')));
-
-        $client = new Client(['adapter' => $mock]);
-        $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('No match');
+        $client = new Client();
+        $this->expectException(MissingResponseException::class);
+        $this->expectExceptionMessage('Unable to find a mock');
 
         $client->post('http://example.com/path');
     }