Repository: lundberg/respx
Pull request #217 (2022-09-15 09:29:23)

Reduce number of `Optional` return values
- Add python `3.11` to nox test ssession
- Runs `mypy` on both tests and respx
- Add `Call.has_response` helper
- Changes `Call.response` to raise instead of being optional
- Changes `CallList.last` to raise instead of being optional
- Changes `M()`, and `Route.pattern`, to not be optional by introducing a `Noop` pattern
- Correctly type hint side effects

codecov-commenter: # [Codecov](https://codecov.io/gh/lundberg/respx/pull/217?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Lundberg) Report
> Merging [#217](https://codecov.io/gh/lundberg/respx/pull/217?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Lundberg) (482b6d7) into [master](https://codecov.io/gh/lundberg/respx/commit/6403618740b559f3e599e824b0985079177ac812?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Lundberg) (6403618) will **not change** coverage.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff            @@
##            master      #217   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           20        20           
  Lines         2740      2795   +55     
  Branches       337       350   +13     
=========================================
+ Hits          2740      2795   +55     
```


| [Impacted Files](https://codecov.io/gh/lundberg/respx/pull/217?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Lundberg) | Coverage Δ | |
|---|---|---|
| [tests/test\_remote.py](https://codecov.io/gh/lundberg/respx/pull/217/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Lundberg#diff-dGVzdHMvdGVzdF9yZW1vdGUucHk=) | `100.00% <ø> (ø)` | |
| [respx/models.py](https://codecov.io/gh/lundberg/respx/pull/217/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Lundberg#diff-cmVzcHgvbW9kZWxzLnB5) | `100.00% <100.00%> (ø)` | |
| [respx/patterns.py](https://codecov.io/gh/lundberg/respx/pull/217/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Lundberg#diff-cmVzcHgvcGF0dGVybnMucHk=) | `100.00% <100.00%> (ø)` | |
| [tests/test\_api.py](https://codecov.io/gh/lundberg/respx/pull/217/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Lundberg#diff-dGVzdHMvdGVzdF9hcGkucHk=) | `100.00% <100.00%> (ø)` | |
| [tests/test\_mock.py](https://codecov.io/gh/lundberg/respx/pull/217/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Lundberg#diff-dGVzdHMvdGVzdF9tb2NrLnB5) | `100.00% <100.00%> (ø)` | |
| [tests/test\_patterns.py](https://codecov.io/gh/lundberg/respx/pull/217/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Lundberg#diff-dGVzdHMvdGVzdF9wYXR0ZXJucy5weQ==) | `100.00% <100.00%> (ø)` | |
| [tests/test\_router.py](https://codecov.io/gh/lundberg/respx/pull/217/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Lundberg#diff-dGVzdHMvdGVzdF9yb3V0ZXIucHk=) | `100.00% <100.00%> (ø)` | |
| [tests/test\_stats.py](https://codecov.io/gh/lundberg/respx/pull/217/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Lundberg#diff-dGVzdHMvdGVzdF9zdGF0cy5weQ==) | `100.00% <100.00%> (ø)` | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Lundberg). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Lundberg)


Patch:
diff --git a/noxfile.py b/noxfile.py
index bc81f3c..35adc7e 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -9,7 +9,7 @@ lint_requirements = ("flake8", "black", "isort")
 docs_requirements = ("mkdocs", "mkdocs-material", "mkautodoc>=0.1.0")
 
 
-@nox.session(python=["3.6", "3.7", "3.8", "3.9", "3.10"])
+@nox.session(python=["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"])
 def test(session):
     deps = ["pytest", "pytest-asyncio", "pytest-cov", "trio", "starlette", "flask"]
     session.install("--upgrade", *deps)
@@ -30,7 +30,7 @@ def check(session):
     session.run("black", "--check", "--diff", "--target-version=py36", *source_files)
     session.run("isort", "--check", "--diff", "--project=respx", *source_files)
     session.run("flake8", *source_files)
-    session.run("mypy", "respx")
+    session.run("mypy")
 
 
 @nox.session
diff --git a/respx/models.py b/respx/models.py
index 44b5e14..cb38b17 100644
--- a/respx/models.py
+++ b/respx/models.py
@@ -44,30 +44,40 @@ def clone_response(response: httpx.Response, request: httpx.Request) -> httpx.Re
 
 class Call(NamedTuple):
     request: httpx.Request
-    response: Optional[httpx.Response]
+    optional_response: Optional[httpx.Response]
+
+    @property
+    def response(self) -> httpx.Response:
+        if self.optional_response is None:
+            raise ValueError(f"{self!r} has no response")
+        return self.optional_response
+
+    @property
+    def has_response(self) -> bool:
+        return self.optional_response is not None
 
 
 class CallList(list, mock.NonCallableMock):
-    def __init__(self, *args, name="respx", **kwargs):
-        super().__init__(*args, **kwargs)
+    def __init__(self, *args: Sequence[Call], name: Any = "respx") -> None:
+        super().__init__(*args)
         mock.NonCallableMock.__init__(self, name=name)
 
     @property
-    def called(self) -> bool:  # type: ignore
+    def called(self) -> bool:  # type: ignore[override]
         return bool(self)
 
     @property
-    def call_count(self) -> int:  # type: ignore
+    def call_count(self) -> int:  # type: ignore[override]
         return len(self)
 
     @property
-    def last(self) -> Optional[Call]:
-        return self[-1] if self else None
+    def last(self) -> Call:
+        return self[-1]
 
     def record(
         self, request: httpx.Request, response: Optional[httpx.Response]
     ) -> Call:
-        call = Call(request=request, response=response)
+        call = Call(request=request, optional_response=response)
         self.append(call)
         return call
 
@@ -155,7 +165,7 @@ class Route:
         raise NotImplementedError("Can't set name on route.")
 
     @property
-    def pattern(self) -> Optional[Pattern]:
+    def pattern(self) -> Pattern:
         return self._pattern
 
     @pattern.setter
@@ -174,7 +184,9 @@ class Route:
         self._return_value = return_value
 
     @property
-    def side_effect(self) -> Optional[SideEffectTypes]:
+    def side_effect(
+        self,
+    ) -> Optional[Union[SideEffectTypes, Sequence[SideEffectListTypes]]]:
         return self._side_effect
 
     @side_effect.setter
@@ -230,7 +242,9 @@ class Route:
         self,
         return_value: Optional[httpx.Response] = None,
         *,
-        side_effect: Optional[SideEffectTypes] = None,
+        side_effect: Optional[
+            Union[SideEffectTypes, Sequence[SideEffectListTypes]]
+        ] = None,
     ) -> "Route":
         self.return_value = return_value
         self.side_effect = side_effect
@@ -430,6 +444,8 @@ class RouteList:
         """
         Re-set all routes to given routes.
         """
+        if (i.start, i.stop, i.step) != (None, None, None):
+            raise TypeError("Can't slice assign routes")
         self._routes = list(routes._routes)
         self._names = dict(routes._names)
 
diff --git a/respx/patterns.py b/respx/patterns.py
index 59a9e4d..106bf90 100644
--- a/respx/patterns.py
+++ b/respx/patterns.py
@@ -88,13 +88,26 @@ class Pattern(ABC):
     def __iter__(self):
         yield self
 
+    def __bool__(self):
+        return True
+
     def __and__(self, other: "Pattern") -> "Pattern":
+        if not bool(other):
+            return self
+        elif not bool(self):
+            return other
         return _And((self, other))
 
     def __or__(self, other: "Pattern") -> "Pattern":
+        if not bool(other):
+            return self
+        elif not bool(self):
+            return other
         return _Or((self, other))
 
     def __invert__(self):
+        if not bool(self):
+            return self
         return _Invert(self)
 
     def __repr__(self):  # pragma: nocover
@@ -159,6 +172,22 @@ class Pattern(ABC):
         return Match(value in self.value)
 
 
+class Noop(Pattern):
+    def __init__(self) -> None:
+        super().__init__(None)
+
+    def __repr__(self):
+        return f"<{self.__class__.__name__}>"
+
+    def __bool__(self) -> bool:
+        # Treat this pattern as non-existent, e.g. when filtering or conditioning
+        return False
+
+    def match(self, request: httpx.Request) -> Match:
+        # If this pattern is part of a combined pattern, always be truthy, i.e. noop
+        return Match(True)
+
+
 class PathPattern(Pattern):
     path: Optional[str]
 
@@ -500,7 +529,7 @@ class Data(ContentMixin, Pattern):
         return data
 
 
-def M(*patterns: Pattern, **lookups: Any) -> Optional[Pattern]:
+def M(*patterns: Pattern, **lookups: Any) -> Pattern:
     extras = None
 
     for pattern__lookup, value in lookups.items():
@@ -550,12 +579,10 @@ def get_scheme_port(scheme: Optional[str]) -> Optional[int]:
     return {"http": 80, "https": 443}.get(scheme or "")
 
 
-def combine(
-    patterns: Sequence[Pattern], op: Callable = operator.and_
-) -> Optional[Pattern]:
+def combine(patterns: Sequence[Pattern], op: Callable = operator.and_) -> Pattern:
     patterns = tuple(filter(None, patterns))
     if not patterns:
-        return None
+        return Noop()
     return reduce(op, patterns)
 
 
@@ -598,14 +625,14 @@ def parse_url_patterns(
     return bases
 
 
-def merge_patterns(pattern: Optional[Pattern], **bases: Pattern) -> Optional[Pattern]:
+def merge_patterns(pattern: Pattern, **bases: Pattern) -> Pattern:
     if not bases:
         return pattern
 
-    if pattern:
-        # Flatten pattern
-        patterns = list(iter(pattern))
+    # Flatten pattern
+    patterns: List[Pattern] = list(filter(None, iter(pattern)))
 
+    if patterns:
         if "host" in (_pattern.key for _pattern in patterns):
             # Pattern is "absolute", skip merging
             bases = {}
diff --git a/setup.cfg b/setup.cfg
index 51b8a0a..1838f0c 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -36,6 +36,10 @@ skip_covered = True
 show_missing = True
 
 [mypy]
+python_version = 3.6
+files = respx,tests
+pretty = True
+
 no_implicit_reexport = True
 no_implicit_optional = True
 strict_equality = True
@@ -53,3 +57,12 @@ show_error_codes = True
 
 [mypy-pytest.*]
 ignore_missing_imports = True
+
+[mypy-trio.*]
+ignore_missing_imports = True
+
+[mypy-flask.*]
+ignore_missing_imports = True
+
+[mypy-starlette.*]
+ignore_missing_imports = True


Test patch:
diff --git a/tests/test_api.py b/tests/test_api.py
index f08f1ab..8b019d8 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -99,7 +99,7 @@ async def test_url_match(client, url, pattern):
 async def test_invalid_url_pattern():
     async with MockRouter() as respx_mock:
         with pytest.raises(TypeError):
-            respx_mock.get(["invalid"])
+            respx_mock.get(["invalid"])  # type: ignore[arg-type]
 
 
 @pytest.mark.asyncio
@@ -277,7 +277,10 @@ async def test_raising_content(client):
     async with MockRouter() as respx_mock:
         url = "https://foo.bar/"
         request = respx_mock.get(url)
-        request.side_effect = httpx.ConnectTimeout("X-P", request=None)
+        request.side_effect = httpx.ConnectTimeout(
+            "X-P",
+            request=None,  # type: ignore[arg-type]
+        )
         with pytest.raises(httpx.ConnectTimeout):
             await client.get(url)
 
@@ -293,7 +296,9 @@ async def test_raising_content(client):
 
         assert route.call_count == 2
         assert route.calls.last.request is not None
-        assert route.calls.last.response is None
+        assert route.calls.last.has_response is False
+        with pytest.raises(ValueError, match="has no response"):
+            assert route.calls.last.response
 
 
 @pytest.mark.asyncio
@@ -356,7 +361,9 @@ async def test_request_callback(client):
         assert response.text == "hello lundberg"
 
         with pytest.raises(TypeError):
-            respx_mock.get("https://ham.spam/").mock(side_effect=lambda req: "invalid")
+            respx_mock.get("https://ham.spam/").mock(
+                side_effect=lambda req: "invalid"  # type: ignore[arg-type,return-value]
+            )
             await client.get("https://ham.spam/")
 
         with pytest.raises(httpx.NetworkError):
@@ -526,10 +533,10 @@ def test_add():
         assert respx.routes["foobar"].called
 
         with pytest.raises(TypeError):
-            respx.add(route, status_code=418)  # pragma: nocover
+            respx.add(route, status_code=418)  # type: ignore[call-arg]
 
         with pytest.raises(ValueError):
-            respx.add("GET")  # pragma: nocover
+            respx.add("GET")  # type: ignore[arg-type]
 
         with pytest.raises(NotImplementedError):
             route.name = "spam"
@@ -554,7 +561,7 @@ def test_respond():
             route.respond(content={})
 
         with pytest.raises(TypeError, match="content can only be"):
-            route.respond(content=Exception())
+            route.respond(content=Exception())  # type: ignore[arg-type]
 
 
 @pytest.mark.asyncio
diff --git a/tests/test_mock.py b/tests/test_mock.py
index 47d5352..ddb85fc 100644
--- a/tests/test_mock.py
+++ b/tests/test_mock.py
@@ -317,25 +317,25 @@ async def test_configured_router_reuse(client):
     with router:
         route.return_value = httpx.Response(202)
         response = await client.get("https://foo/bar/")
-        assert route.called is True
+        assert route.called == True  # noqa: E712
         assert response.status_code == 202
         assert router.calls.call_count == 1
         assert respx.calls.call_count == 0
 
     assert len(router.routes) == 1
-    assert route.called is False
+    assert route.called == False  # noqa: E712
     assert router.calls.call_count == 0
 
     async with router:
         assert router.calls.call_count == 0
         response = await client.get("https://foo/bar/")
-        assert route.called is True
+        assert route.called == True  # noqa: E712
         assert response.status_code == 404
         assert router.calls.call_count == 1
         assert respx.calls.call_count == 0
 
     assert len(router.routes) == 1
-    assert route.called is False
+    assert route.called == False  # noqa: E712
     assert router.calls.call_count == 0
     assert respx.calls.call_count == 0
 
@@ -346,7 +346,7 @@ async def test_router_return_type_misuse():
     route = router.get("https://hot.dog/")
 
     with pytest.raises(TypeError):
-        route.return_value = "not-a-httpx-response"
+        route.return_value = "not-a-httpx-response"  # type: ignore[assignment]
 
 
 @pytest.mark.asyncio
@@ -396,7 +396,7 @@ async def test_start_stop(client):
     try:
         respx.start()
         response = await client.get(url)
-        assert request.called is True
+        assert request.called == True  # noqa: E712
         assert response.status_code == 202
         assert response.text == ""
         assert respx.calls.call_count == 1
@@ -404,12 +404,12 @@ async def test_start_stop(client):
         respx.stop(clear=False, reset=False)
         assert len(respx.routes) == 1
         assert respx.calls.call_count == 1
-        assert request.called is True
+        assert request.called == True  # noqa: E712
 
         respx.reset()
         assert len(respx.routes) == 1
         assert respx.calls.call_count == 0
-        assert request.called is False
+        assert request.called == False  # noqa: E712
 
         respx.clear()
         assert len(respx.routes) == 0
@@ -545,7 +545,7 @@ async def test_router_using__none():
 
 def test_router_using__invalid():
     with pytest.raises(ValueError, match="using"):
-        respx.MockRouter(using=123).using
+        respx.MockRouter(using=123).using  # type: ignore[arg-type]
 
 
 def test_mocker_subclass():
diff --git a/tests/test_patterns.py b/tests/test_patterns.py
index f90c561..f846654 100644
--- a/tests/test_patterns.py
+++ b/tests/test_patterns.py
@@ -15,6 +15,7 @@ from respx.patterns import (
     Lookup,
     M,
     Method,
+    Noop,
     Params,
     Path,
     Pattern,
@@ -66,6 +67,18 @@ def test_match_context():
     assert match.context == {"host": "foo.bar", "slug": "baz"}
 
 
+def test_noop_pattern():
+    assert bool(Noop()) is False
+    assert bool(Noop().match(httpx.Request("GET", "https://example.org"))) is True
+    assert list(filter(None, [Noop()])) == []
+    assert repr(Noop()) == "<Noop>"
+    assert isinstance(~Noop(), Noop)
+    assert Method("GET") & Noop() == Method("GET")
+    assert Noop() & Method("GET") == Method("GET")
+    assert Method("GET") | Noop() == Method("GET")
+    assert Noop() | Method("GET") == Method("GET")
+
+
 @pytest.mark.parametrize(
     "kwargs,url,expected",
     [
diff --git a/tests/test_remote.py b/tests/test_remote.py
index 0bdfa6e..a12c229 100644
--- a/tests/test_remote.py
+++ b/tests/test_remote.py
@@ -37,7 +37,7 @@ def test_remote_pass_through(using, client_lib, call_count):  # pragma: nocover
         assert response.json()["json"] == {"foo": "bar"}
 
         assert respx_mock.calls.last.request.url == url
-        assert respx_mock.calls.last.response is None
+        assert respx_mock.calls.last.has_response is False
 
         assert route.call_count == call_count
         assert respx_mock.calls.call_count == call_count
diff --git a/tests/test_router.py b/tests/test_router.py
index 6bec1fe..f7549c0 100644
--- a/tests/test_router.py
+++ b/tests/test_router.py
@@ -29,11 +29,13 @@ async def test_empty_router__auto_mocked():
     resolved = router.resolve(request)
 
     assert resolved.route is None
+    assert isinstance(resolved.response, httpx.Response)
     assert resolved.response.status_code == 200
 
     resolved = await router.aresolve(request)
 
     assert resolved.route is None
+    assert isinstance(resolved.response, httpx.Response)
     assert resolved.response.status_code == 200
 
 
@@ -62,6 +64,7 @@ def test_resolve(args, kwargs, expected):
     resolved = router.resolve(request)
 
     assert bool(resolved.route is route) is expected
+    assert isinstance(resolved.response, httpx.Response)
     if expected:
         assert bool(resolved.response.status_code == 201) is expected
     else:
@@ -82,6 +85,7 @@ def test_pass_through():
     route.pass_through(False)
     resolved = router.resolve(request)
 
+    assert resolved.route is not None
     assert resolved.route is route
     assert not resolved.route.is_pass_through
     assert resolved.response is not None
@@ -106,6 +110,7 @@ def test_base_url(url, lookups, expected):
     resolved = router.resolve(request)
 
     assert bool(resolved.route is route) is expected
+    assert isinstance(resolved.response, httpx.Response)
     if expected:
         assert bool(resolved.response.status_code == 201) is expected
     else:
@@ -151,23 +156,26 @@ def test_mod_response():
 
     request = httpx.Request("GET", "https://foo.bar/baz/")
     resolved = router.resolve(request)
+    assert isinstance(resolved.response, httpx.Response)
     assert resolved.response.status_code == 404
     assert resolved.route is route1b
     assert route1a is route1b
 
     request = httpx.Request("GET", "https://foo.bar/")
     resolved = router.resolve(request)
+    assert isinstance(resolved.response, httpx.Response)
     assert resolved.response.status_code == 201
     assert resolved.route is route2
 
     request = httpx.Request("POST", "https://fox.zoo/")
     resolved = router.resolve(request)
+    assert isinstance(resolved.response, httpx.Response)
     assert resolved.response.status_code == 401
     assert resolved.response.json() == {"error": "x"}
     assert resolved.route is route3
 
     with pytest.raises(TypeError, match="Route can only"):
-        router.route() % []
+        router.route() % []  # type: ignore[operator]
 
 
 @pytest.mark.asyncio
@@ -197,7 +205,7 @@ def test_side_effect_no_match():
     request = httpx.Request("GET", "https://foo.bar/baz/")
     response = router.handler(request)
     assert response.status_code == 204
-    assert response.request.respx_was_here is True
+    assert response.request.respx_was_here is True  # type: ignore[attr-defined]
 
 
 def test_side_effect_with_route_kwarg():
@@ -379,12 +387,12 @@ def test_rollback():
 
     assert len(router.routes) == 1
     assert router.calls.call_count == 0
-    assert route.return_value is None
+    assert route.return_value == None  # noqa: E711
 
     router.rollback()  # Empty initial state
 
     assert len(router.routes) == 0
-    assert route.return_value is None
+    assert route.return_value == None  # noqa: E711
 
     # Idempotent
     route.rollback()
@@ -523,3 +531,9 @@ def test_routelist__replaces_same_name_other_pattern_other_name():
     routes.add(foobar2, name="foobar")
     assert list(routes) == [foobar2]
     assert routes["foobar"] is foobar1
+
+
+def test_routelist__unable_to_slice_assign():
+    routes = RouteList()
+    with pytest.raises(TypeError, match="slice assign"):
+        routes[0:1] = routes
diff --git a/tests/test_stats.py b/tests/test_stats.py
index 4089d34..68ef6d4 100644
--- a/tests/test_stats.py
+++ b/tests/test_stats.py
@@ -18,7 +18,7 @@ async def test_named_route():
 
 
 @respx.mock
-async def backend_test(backend):
+async def backend_test():
     url = "https://foo.bar/1/"
     respx.get(re.compile("https://some.thing"))
     respx.delete("https://some.thing")
@@ -26,10 +26,11 @@ async def backend_test(backend):
     foobar1 = respx.get(url, name="get_foobar") % dict(status_code=202, text="get")
     foobar2 = respx.delete(url, name="del_foobar") % dict(text="del")
 
-    assert foobar1.called is False
+    assert foobar1.called == False  # noqa: E712
     assert foobar1.call_count == len(foobar1.calls)
     assert foobar1.call_count == 0
-    assert foobar1.calls.last is None
+    with pytest.raises(IndexError):
+        foobar1.calls.last
     assert respx.calls.call_count == len(respx.calls)
     assert respx.calls.call_count == 0
 
@@ -43,8 +44,8 @@ async def backend_test(backend):
         get_response = await client.get(url)
         del_response = await client.delete(url)
 
-    assert foobar1.called is True
-    assert foobar2.called is True
+    assert foobar1.called == True  # noqa: E712
+    assert foobar2.called == True  # noqa: E712
     assert foobar1.call_count == 1
     assert foobar2.call_count == 1
     assert foobar1.calls.call_count == 1
@@ -92,19 +93,14 @@ async def backend_test(backend):
 def test_asyncio():
     import asyncio
 
-    from httpcore.backends.asyncio import AsyncIOBackend
-
-    backend = AsyncIOBackend()  # TODO: Why instantiate a backend?
     loop = asyncio.new_event_loop()
     try:
-        loop.run_until_complete(backend_test(backend))
+        loop.run_until_complete(backend_test())
     finally:
         loop.close()
 
 
 def test_trio():  # pragma: nocover
     import trio
-    from httpcore.backends.trio import TrioBackend
 
-    backend = TrioBackend()  # TODO: Why instantiate a backend?
-    trio.run(backend_test, backend)
+    trio.run(backend_test)