diff --git a/respx/mock.py b/respx/mock.py
index c3f45e5..fd62371 100644
--- a/respx/mock.py
+++ b/respx/mock.py
@@ -24,8 +24,11 @@ __all__ = ["HTTPXMock"]
 
 
 class HTTPXMock:
-    def __init__(self, assert_all_called: bool = True) -> None:
+    def __init__(
+        self, assert_all_called: bool = True, assert_all_mocked: bool = True
+    ) -> None:
         self._assert_all_called = assert_all_called
+        self._assert_all_mocked = assert_all_mocked
         self._patchers: typing.List[asynctest.mock._patch] = []
         self._patterns: typing.List[RequestPattern] = []
         self.aliases: typing.Dict[str, RequestPattern] = {}
@@ -93,7 +96,7 @@ class HTTPXMock:
     def assert_all_called(self):
         assert all(
             (pattern.called for pattern in self._patterns)
-        ), "not all requests called"
+        ), "RESPX: some mocked requests were not called!"
 
     def add(self, pattern: RequestPattern, alias: typing.Optional[str] = None) -> None:
         self._patterns.append(pattern)
@@ -143,29 +146,29 @@ class HTTPXMock:
     ) -> typing.Tuple[
         typing.Optional[RequestPattern], typing.Optional[ResponseTemplate]
     ]:
-        found_index: typing.Optional[int] = None
         matched_pattern: typing.Optional[RequestPattern] = None
-        matched_response: typing.Optional[ResponseTemplate] = None
+        matched_pattern_index: typing.Optional[int] = None
+        response: typing.Optional[ResponseTemplate] = None
 
         for i, pattern in enumerate(self._patterns):
             match = pattern.match(request)
             if not match:
                 continue
 
-            if found_index is not None:
+            if matched_pattern_index is not None:
                 # Multiple matches found, drop and use the first one
-                self._patterns.pop(found_index)
+                self._patterns.pop(matched_pattern_index)
                 break
 
-            found_index = i
             matched_pattern = pattern
+            matched_pattern_index = i
 
             if isinstance(match, ResponseTemplate):
                 # Mock response
-                matched_response = match
+                response = match
             elif isinstance(match, AsyncRequest):
                 # Pass-through request
-                matched_response = None
+                response = None
             else:
                 raise ValueError(
                     (
@@ -174,7 +177,17 @@ class HTTPXMock:
                     ).format(type(match))
                 )
 
-        return matched_pattern, matched_response
+        # Assert we always get a pattern match, if check is enabled
+        assert (
+            not self._assert_all_mocked
+            or self._assert_all_mocked
+            and matched_pattern is not None
+        ), f"RESPX: {request!r} not mocked!"
+
+        if matched_pattern is None:
+            response = ResponseTemplate()
+
+        return matched_pattern, response
 
     @contextmanager
     def _patch_backend(
@@ -226,15 +239,11 @@ class HTTPXMock:
         and mocks client backend open stream methods.
         """
         # 1. Match request against added patterns
-        pattern, template = self._match(request)
-
-        if pattern is None:
-            template = ResponseTemplate()
+        pattern, _response = self._match(request)
 
         # 2. Patch client's backend and continue to original _get_response
         try:
-            global _get_response
-            with self._patch_backend(client.concurrency_backend, request, template):
+            with self._patch_backend(client.concurrency_backend, request, _response):
                 response = None
                 response = await _get_response(client, request, **kwargs)
         finally:

Raise on non-matching request
Add setting to raise an exception when a request is captured but not matching any added pattern, with the possibility to disable/enable the feature.

Decide what the default behaviour should be, raise or always mock responses.

What exception should be raised, `AssertionError` or `ConnectionError`?

**Idea**:
```py
with respx.HTTPXMock(assert_all_mocked=False):
    respx.get("https://foo/bar/")
    httpx.get("https://ham/spam/")  # Would raise an AssertionError("non-matching")
```
diff --git a/tests/test_mock.py b/tests/test_mock.py
index 9624c47..97fd913 100644
--- a/tests/test_mock.py
+++ b/tests/test_mock.py
@@ -106,9 +106,11 @@ class HTTPXMockTestCase(asynctest.TestCase):
         self.assertFalse(foobar.called)
 
     def test_unknown_url(self):
-        with respx.mock():
+        with respx.HTTPXMock(
+            assert_all_called=False, assert_all_mocked=False
+        ) as httpx_mock:
             url = "https://foo/bar/"
-            foobar = respx.post(url)  # Non-matching method
+            foobar = httpx_mock.post(url)  # Non-matching method
             response = httpx.get(url)
 
             self.assertFalse(foobar.called)
@@ -118,8 +120,8 @@ class HTTPXMockTestCase(asynctest.TestCase):
             )
             self.assertEqual(response.text, "")
 
-            self.assertEqual(len(respx.calls), 1)
-            request, response = respx.calls[-1]
+            self.assertEqual(len(httpx_mock.calls), 1)
+            request, response = httpx_mock.calls[-1]
             self.assertIsNotNone(request)
             self.assertIsNotNone(response)
 
@@ -294,6 +296,7 @@ class HTTPXMockTestCase(asynctest.TestCase):
                 side_effect=ValueError("mock"),
             ):
                 url = "https://foo/bar/1/"
+                httpx_mock.get(url)
                 with self.assertRaises(ValueError):
                     httpx.get(url)
 
@@ -310,7 +313,9 @@ class HTTPXMockTestCase(asynctest.TestCase):
                 return response
 
         with respx.HTTPXMock(assert_all_called=False) as httpx_mock:
-            request = httpx_mock.request(matcher, status_code=202, headers={"X-Ham": "Spam"})
+            request = httpx_mock.request(
+                matcher, status_code=202, headers={"X-Ham": "Spam"}
+            )
             response = httpx.get("https://foo/bar/")
 
             self.assertEqual(response.status_code, 202)
@@ -361,6 +366,20 @@ class HTTPXMockTestCase(asynctest.TestCase):
             self.assertTrue(request1.called)
             self.assertTrue(request2.called)
 
+    def test_assert_all_mocked_fail(self):
+        with self.assertRaises(AssertionError):
+            with respx.HTTPXMock(assert_all_mocked=True) as httpx_mock:
+                httpx.get("https://foo/bar/")
+
+        self.assertEqual(len(httpx_mock.calls), 0)
+
+    def test_assert_all_mocked_disabled(self):
+        with respx.HTTPXMock(assert_all_mocked=False) as httpx_mock:
+            response = httpx.get("https://foo/bar/")
+
+            self.assertEqual(response.status_code, 200)
+            self.assertEqual(len(httpx_mock.calls), 1)
+
     def test_pass_through_with_arg(self):
         with respx.mock():
             request = respx.get("https://www.example.org/", pass_through=True)

pip install -e .
parse_log_pytest
pytest
pytest pytest-asyncio pytest-cov trio
3.8
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
asynctest==0.13.0
attrs==25.3.0
certifi==2025.1.31
chardet==3.0.4
coverage==7.6.1
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
h11==0.8.1
h2==3.2.0
hpack==3.0.0
hstspreload==2025.1.1
httpx==0.7.6
hyperframe==5.2.0
idna==2.10
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
outcome==1.3.0.post0
packaging @ file:///croot/packaging_1720101850331/work
pluggy==1.5.0
pytest==8.3.5
pytest-asyncio==0.24.0
pytest-cov==5.0.0
-e git+https://github.com/lundberg/respx.git@3e36da0d783a0bc143df9828a0e61c148f0fbc0c#egg=respx
rfc3986==1.5.0
sniffio==1.3.1
sortedcontainers==2.4.0
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
trio==0.27.0

name: respx
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - exceptiongroup=1.2.0=py38h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.1=py38h06a4308_0
  - pip=24.2=py38h06a4308_0
  - python=3.8.20=he870216_0
  - readline=8.2=h5eee18b_0
  - setuptools=75.1.0=py38h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py38h06a4308_0
  - wheel=0.44.0=py38h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - asynctest==0.13.0
      - attrs==25.3.0
      - certifi==2025.1.31
      - chardet==3.0.4
      - coverage==7.6.1
      - h11==0.8.1
      - h2==3.2.0
      - hpack==3.0.0
      - hstspreload==2025.1.1
      - httpx==0.7.6
      - hyperframe==5.2.0
      - idna==2.10
      - outcome==1.3.0.post0
      - pluggy==1.5.0
      - pytest==8.3.5
      - pytest-asyncio==0.24.0
      - pytest-cov==5.0.0
      - rfc3986==1.5.0
      - sniffio==1.3.1
      - sortedcontainers==2.4.0
      - trio==0.27.0
prefix: /opt/conda/envs/respx

tests/test_mock.py::HTTPXMockTestCase::test_assert_all_mocked_disabled tests/test_mock.py::HTTPXMockTestCase::test_assert_all_mocked_fail tests/test_mock.py::HTTPXMockTestCase::test_unknown_url
tests/test_mock.py::HTTPXMockTestCase::test_alias tests/test_mock.py::HTTPXMockTestCase::test_api tests/test_mock.py::HTTPXMockTestCase::test_assert_all_called_disabled tests/test_mock.py::HTTPXMockTestCase::test_assert_all_called_fail tests/test_mock.py::HTTPXMockTestCase::test_assert_all_called_sucess tests/test_mock.py::HTTPXMockTestCase::test_async_client tests/test_mock.py::HTTPXMockTestCase::test_callable_content tests/test_mock.py::HTTPXMockTestCase::test_content_type tests/test_mock.py::HTTPXMockTestCase::test_custom_matcher tests/test_mock.py::HTTPXMockTestCase::test_exception tests/test_mock.py::HTTPXMockTestCase::test_headers tests/test_mock.py::HTTPXMockTestCase::test_http_methods tests/test_mock.py::HTTPXMockTestCase::test_invalid_url_pattern tests/test_mock.py::HTTPXMockTestCase::test_json_content tests/test_mock.py::HTTPXMockTestCase::test_mock_contextmanager tests/test_mock.py::HTTPXMockTestCase::test_mock_decorator tests/test_mock.py::HTTPXMockTestCase::test_pass_through_with_arg tests/test_mock.py::HTTPXMockTestCase::test_pass_through_with_custom_matcher tests/test_mock.py::HTTPXMockTestCase::test_raising_content tests/test_mock.py::HTTPXMockTestCase::test_raw_content tests/test_mock.py::HTTPXMockTestCase::test_regex_url_pattern tests/test_mock.py::HTTPXMockTestCase::test_repeated_pattern tests/test_mock.py::HTTPXMockTestCase::test_stats tests/test_mock.py::HTTPXMockTestCase::test_status_code tests/test_mock.py::HTTPXMockTestCase::test_string_url_pattern tests/test_mock.py::HTTPXMockTestCase::test_sync_client tests/test_mock.py::HTTPXMockTestCase::test_trio_backend
respx/mock.py
respx/mock.py