Repository: getsentry/responses
Pull request #318 (2020-04-11 16:41:07)

Added assert_called_once.

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

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

```diff
@@            Coverage Diff             @@
##           master     #318      +/-   ##
==========================================
+ Coverage   95.85%   95.94%   +0.08%     
==========================================
  Files           3        3              
  Lines        1158     1183      +25     
==========================================
+ Hits         1110     1135      +25     
  Misses         48       48              
```


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

------

[Continue to review full report at Codecov](https://codecov.io/gh/getsentry/responses/pull/318?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/318?src=pr&el=footer). Last update [7adbc38...139c62b](https://codecov.io/gh/getsentry/responses/pull/318?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/README.rst b/README.rst
index c5264b1..0cd6ce8 100644
--- a/README.rst
+++ b/README.rst
@@ -315,6 +315,28 @@ the ``assert_all_requests_are_fired`` value:
                      body='{}', status=200,
                      content_type='application/json')
 
+assert_call_count
+-----------------
+
+Assert that the request was called exactly n times.
+
+.. code-block:: python
+
+    import responses
+    import requests
+
+    @responses.activate
+    def test_assert_call_count():
+        responses.add(responses.GET, "http://example.com")
+
+        requests.get("http://example.com")
+        assert responses.assert_call_count("http://example.com", 1) is True
+
+        requests.get("http://example.com")
+        with pytest.raises(AssertionError) as excinfo:
+            responses.assert_call_count("http://example.com", 1)
+        assert "Expected URL 'http://example.com' to be called 1 times. Called 2 times." in str(excinfo.value)
+
 
 Multiple Responses
 ------------------
diff --git a/responses.py b/responses.py
index d0d24b6..d5b4325 100644
--- a/responses.py
+++ b/responses.py
@@ -692,6 +692,23 @@ class RequestsMock(object):
                 )
             )
 
+    def assert_call_count(self, url, count):
+        call_count = len(
+            [
+                1
+                for call in self.calls
+                if call.request.url == _ensure_url_default_path(url)
+            ]
+        )
+        if call_count == count:
+            return True
+        else:
+            raise AssertionError(
+                "Expected URL '{0}' to be called {1} times. Called {2} times.".format(
+                    url, count, call_count
+                )
+            )
+
 
 # expose default mock namespace
 mock = _default_mock = RequestsMock(assert_all_requests_are_fired=False)
@@ -705,6 +722,7 @@ __all__ = [
     "add_callback",
     "add_passthru",
     "assert_all_requests_are_fired",
+    "assert_call_count",
     "calls",
     "DELETE",
     "GET",
@@ -728,6 +746,7 @@ add = _default_mock.add
 add_callback = _default_mock.add_callback
 add_passthru = _default_mock.add_passthru
 assert_all_requests_are_fired = _default_mock.assert_all_requests_are_fired
+assert_call_count = _default_mock.assert_call_count
 calls = _default_mock.calls
 DELETE = _default_mock.DELETE
 GET = _default_mock.GET


Test patch:
diff --git a/test_responses.py b/test_responses.py
index 6f0162e..9a22776 100644
--- a/test_responses.py
+++ b/test_responses.py
@@ -1150,3 +1150,37 @@ def test_request_param(url):
 
     run()
     assert_reset()
+
+
+@pytest.mark.parametrize(
+    "url", ("http://example.com", "http://example.com?hello=world")
+)
+def test_assert_call_count(url):
+    @responses.activate
+    def run():
+        responses.add(responses.GET, url)
+        responses.add(responses.GET, "http://example1.com")
+
+        assert responses.assert_call_count(url, 0) is True
+
+        with pytest.raises(AssertionError) as excinfo:
+            responses.assert_call_count(url, 2)
+        assert "Expected URL '{0}' to be called 2 times. Called 0 times.".format(
+            url
+        ) in str(excinfo.value)
+
+        requests.get(url)
+        assert responses.assert_call_count(url, 1) is True
+
+        requests.get("http://example1.com")
+        assert responses.assert_call_count(url, 1) is True
+
+        requests.get(url)
+        with pytest.raises(AssertionError) as excinfo:
+            responses.assert_call_count(url, 3)
+        assert "Expected URL '{0}' to be called 3 times. Called 2 times.".format(
+            url
+        ) in str(excinfo.value)
+
+    run()
+    assert_reset()