0

I have a few Django Rest Framework API endpoints I want to test.

They are behind an authenticated page. I'm trying to use the DRF RequestsClient to do that.

My code looks like this:

from rest_framework.test import APITestCase from rest_framework.test import RequestsClient from django.urls import reverse import requests URL_PREFIX="http://testserver" API_TOKEN="tfhgffhgf675h" class APITests(APITestCase): @staticmethod def _get_full_url(url, *args, **kwargs): return URL_PREFIX + reverse(url, *args, **kwargs) def setUp(self): self.client = RequestsClient() def test_stuff(self): url = self._get_full_url("ahs:agena_results-list") # Raw requests library - works fine # Note: Testing shows that the RequestsClient() seems to do some sort of magic to # be able to resolve http://testserver. A raw requests GET request must hit it at # 127.0.0.1, and specify the port response = requests.get("http://127.0.0.1:8000", headers={"Authorization": f"Token {API_TOKEN}"}) # RequestsClient() - doesn't work response = self.client.get(url, headers={"Authorization": f"Token {API_TOKEN}"}) 

My RequestsClient request doesn't work, but my raw requests request works fine.

The exception raised when using the RequestsClient is pretty cryptic:

Internal Server Error: /ahs/api/agena_results/ Traceback (most recent call last): File "/usr/local/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1361, in execute_sql cursor.execute(sql, params) File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 67, in execute return self._execute_with_wrappers( File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers return executor(sql, params, many, context) File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 83, in _execute self.db.validate_no_broken_transaction() File "/usr/local/lib/python3.9/site-packages/django/db/backends/base/base.py", line 480, in validate_no_broken_transaction raise TransactionManagementError( django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block. During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 55, in inner response = get_response(request) File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 197, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/usr/local/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view return view_func(*args, **kwargs) File "/usr/local/lib/python3.9/site-packages/rest_framework/viewsets.py", line 125, in view return self.dispatch(request, *args, **kwargs) File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 509, in dispatch response = self.handle_exception(exc) File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 469, in handle_exception self.raise_uncaught_exception(exc) File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception raise exc File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 497, in dispatch self.initial(request, *args, **kwargs) File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 414, in initial self.perform_authentication(request) File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 324, in perform_authentication request.user File "/usr/local/lib/python3.9/site-packages/rest_framework/request.py", line 227, in user self._authenticate() File "/usr/local/lib/python3.9/site-packages/rest_framework/request.py", line 380, in _authenticate user_auth_tuple = authenticator.authenticate(self) File "/usr/local/lib/python3.9/site-packages/rest_framework/authentication.py", line 196, in authenticate return self.authenticate_credentials(token) File "/usr/local/lib/python3.9/site-packages/rest_framework/authentication.py", line 201, in authenticate_credentials token = model.objects.select_related('user').get(key=key) File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 492, in get num = len(clone) File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 302, in __len__ self._fetch_all() File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 1507, in _fetch_all self._result_cache = list(self._iterable_class(self)) File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 57, in __iter__ results = compiler.execute_sql( File "/usr/local/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1364, in execute_sql cursor.close() File "/usr/local/lib/python3.9/site-packages/MySQLdb/cursors.py", line 83, in close while self.nextset(): File "/usr/local/lib/python3.9/site-packages/MySQLdb/cursors.py", line 137, in nextset nr = db.next_result() MySQLdb._exceptions.OperationalError: (2006, '') . ---------------------------------------------------------------------- Ran 1 test in 30.774s 

The strange thing is that if I remove the Authorization header from the RequestsClient request, it doesn't crash, but does return a 403, so that doesn't help me.

I also tried setting the Authorization header on the RequestsClient this way, but that didn't help either:

self.client.headers.update({'Authorization': f'Token {API_TOKEN}'}) 

Any idea what I'm doing wrong?

5
  • duplicate question stackoverflow.com/questions/21458387/… Commented Jun 24, 2022 at 13:12
  • Does this answer your question? TransactionManagementError "You can't execute queries until the end of the 'atomic' block" while using signals, but only during Unit Testing Commented Jun 24, 2022 at 13:13
  • @Pfinnn thanks for the link. I came across that one before I posted. Most of the answers are close to 10 years old, and wrapping my request in a transaction.atomic didn't help. Is there something else I can try? Commented Jun 24, 2022 at 14:01
  • there are many answers on that thread. Did you read them? The accepted answer suggests wrapping the transaction in with.transaction.atomic(): Also read here, maybe this will help: docs.djangoproject.com/en/4.0/topics/db/transactions Commented Jun 24, 2022 at 14:16
  • @Pfinnn transaction.atomic (from the top accepted answer) didn't help. Using APITransactionTestCase (from the second top accepted answer) didn't help. Not surprising since both answers are really, really, old. Every other answer appears to be just guessing at what it might be. Is there something specific I can try? Commented Jun 24, 2022 at 19:01

1 Answer 1

0

Using APILiveServerTestCase instead of APITestCase when using RequestsClient solves the problem.

Apparently, the poor documentation around this has been known for some time now, but does not appear to have improved since then.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.