Skip to content

Commit 1964929

Browse files
committed
Add TestDataManager utility, modified TestClient
1 parent c4c0883 commit 1964929

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

django_utils_lib/testing/utils.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
import re
44
from typing import List, Tuple, Union, cast
5+
from unittest import TestCase
56

67
import pytest
8+
from django.contrib.auth import authenticate
9+
from django.http import HttpRequest
10+
from django.test.client import Client as _TestClient
711
from typing_extensions import TypedDict
812
from xdist import is_xdist_worker
913

@@ -81,3 +85,56 @@ def validate_requirement_tagging(item: pytest.Item) -> RequirementValidationResu
8185
"errors": errors,
8286
"validated_requirements": validated_requirements,
8387
}
88+
89+
90+
class TestClient(_TestClient):
91+
"""
92+
A Wrapper around Django's default TestClient to add a few extra features,
93+
such as compatibility with `django-axes`
94+
"""
95+
96+
# This is so that Pytest doesn't think this is itself a test
97+
__test__ = False
98+
99+
def login(self, client_ip="127.0.0.1", **credentials) -> bool:
100+
"""
101+
This overrides the `login` method from `ClientMixin`, to get it to work with
102+
the `django-axes` middleware, which requires a `HttpRequest` object as part of the
103+
authentication flow.
104+
"""
105+
request = HttpRequest()
106+
request.META = {"REMOTE_ADDR": client_ip}
107+
user = authenticate(request=request, **credentials)
108+
if user:
109+
self._login(user) # type: ignore[attr-defined]
110+
return True
111+
return False
112+
113+
114+
class TestDataManager(TestCase):
115+
'''
116+
Wrapper class to help manage test data through the lifecycle of a test
117+
118+
The normal pattern for using this would be sub-class it, and then expose it
119+
as a injected fixture. E.g.:
120+
121+
```python
122+
class MyTestDataManager(TestDataManager):
123+
pass
124+
125+
@pytest.fixture
126+
def test_data(db) -> TestDataManager:
127+
"""
128+
Fixture wrapper around test data manager
129+
"""
130+
return TestDataManager()
131+
```
132+
'''
133+
134+
# Note: This overrides the default of the parent class, to use our
135+
# modified TestClient
136+
client: TestClient
137+
138+
def __init__(self) -> None:
139+
super().__init__()
140+
self.client = TestClient()

0 commit comments

Comments
 (0)