Repository: getsentry/responses
Pull request #349 (2020-10-07 14:04:58)

Improve ConnectionError error message.
Fixes https://github.com/getsentry/responses/issues/345

codecov[bot]: # [Codecov](https://codecov.io/gh/getsentry/responses/pull/349?src=pr&el=h1) Report
> Merging [#349](https://codecov.io/gh/getsentry/responses/pull/349?src=pr&el=desc) into [master](https://codecov.io/gh/getsentry/responses/commit/ff202ea21ce044215f1904989e5ed2e404354e8f?el=desc) will **increase** coverage by `0.05%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/getsentry/responses/pull/349/graphs/tree.svg?width=650&height=150&src=pr&token=x2tAGR7rxE)](https://codecov.io/gh/getsentry/responses/pull/349?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #349      +/-   ##
==========================================
+ Coverage   96.10%   96.15%   +0.05%     
==========================================
  Files           3        3              
  Lines        1231     1248      +17     
==========================================
+ Hits         1183     1200      +17     
  Misses         48       48              
```


| [Impacted Files](https://codecov.io/gh/getsentry/responses/pull/349?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [responses.py](https://codecov.io/gh/getsentry/responses/pull/349/diff?src=pr&el=tree#diff-cmVzcG9uc2VzLnB5) | `97.62% <100.00%> (+0.01%)` | :arrow_up: |
| [test\_responses.py](https://codecov.io/gh/getsentry/responses/pull/349/diff?src=pr&el=tree#diff-dGVzdF9yZXNwb25zZXMucHk=) | `97.76% <100.00%> (+0.03%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/getsentry/responses/pull/349?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/getsentry/responses/pull/349?src=pr&el=footer). Last update [ff202ea...258c9d8](https://codecov.io/gh/getsentry/responses/pull/349?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/responses.py b/responses.py
index b1bac99..1e29383 100644
--- a/responses.py
+++ b/responses.py
@@ -357,15 +357,15 @@ class BaseResponse(object):
 
     def matches(self, request):
         if request.method != self.method:
-            return False
+            return False, "Method does not match"
 
         if not self._url_matches(self.url, request.url, self.match_querystring):
-            return False
+            return False, "URL does not match"
 
         if not self._body_matches(self.match, request.body):
-            return False
+            return False, "Parameters do not match"
 
-        return True
+        return True, ""
 
 
 class Response(BaseResponse):
@@ -653,16 +653,19 @@ class RequestsMock(object):
     def _find_match(self, request):
         found = None
         found_match = None
+        match_failed_reasons = []
         for i, match in enumerate(self._matches):
-            if match.matches(request):
+            match_result, reason = match.matches(request)
+            if match_result:
                 if found is None:
                     found = i
                     found_match = match
                 else:
                     # Multiple matches found.  Remove & return the first match.
-                    return self._matches.pop(found)
-
-        return found_match
+                    return self._matches.pop(found), match_failed_reasons
+            else:
+                match_failed_reasons.append(reason)
+        return found_match, match_failed_reasons
 
     def _parse_request_params(self, url):
         params = {}
@@ -674,7 +677,7 @@ class RequestsMock(object):
         return params
 
     def _on_request(self, adapter, request, **kwargs):
-        match = self._find_match(request)
+        match, match_failed_reasons = self._find_match(request)
         resp_callback = self.response_callback
         request.params = self._parse_request_params(request.path_url)
 
@@ -697,8 +700,10 @@ class RequestsMock(object):
                 "- %s %s\n\n"
                 "Available matches:\n" % (request.method, request.url)
             )
-            for m in self._matches:
-                error_msg += "- {} {}\n".format(m.method, m.url)
+            for i, m in enumerate(self._matches):
+                error_msg += "- {} {} {}\n".format(
+                    m.method, m.url, match_failed_reasons[i]
+                )
 
             response = ConnectionError(error_msg)
             response.request = request


Test patch:
diff --git a/test_responses.py b/test_responses.py
index 5783de9..02089b9 100644
--- a/test_responses.py
+++ b/test_responses.py
@@ -1277,3 +1277,25 @@ def test_request_matches_empty_body():
 
     run()
     assert_reset()
+
+
+def test_fail_request_error():
+    @responses.activate
+    def run():
+        responses.add("POST", "http://example1.com")
+        responses.add("GET", "http://example.com")
+        responses.add(
+            "POST",
+            "http://example.com",
+            match=[responses.urlencoded_params_matcher({"foo": "bar"})],
+        )
+
+        with pytest.raises(ConnectionError) as excinfo:
+            requests.post("http://example.com", data={"id": "bad"})
+        msg = str(excinfo.value)
+        assert "- POST http://example1.com/ URL does not match" in msg
+        assert "- GET http://example.com/ Method does not match" in msg
+        assert "- POST http://example.com/ Parameters do not match" in msg
+
+    run()
+    assert_reset()