I'm writing a Django app that uses a REST api I created. The purpose is to prove api use cases using the web app. In my view, I therefore call the api using the python-requests library like so:
def my_view_method(request):
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
data = form.cleaned_data
data_to_post = {
'fieldA': data.get('fieldA_in_form'),
'fieldB': data.get('fieldB_in_form'),
}
post_url = "http://%s/%s/" % (request.get_host(), 'entries')
logger.info("request api url: "+ post_url)
r = requests.post(post_url, data=data_to_post)
return HttpResponseRedirect('/')
else:
form = MyForm()
return render(request, 'myview.html', { 'form': form })
I have verified using Unit Tests that POSTing to /entries/ with valid data results in the correct database updates.
url = '/entries/'
#verify initial db state
data = { 'fieldA': value1, 'fieldB': value2 }
response = self.client.post(url, data, format='json')
# verify db was updated
In my Functional Tests, I use LiveServerTestCase and interact with the Form. When the test submits the form, the browser tab shows "Connecting..." in the title and the test case hangs. It wasn't so when I was directly interacting with the database instead of calling the api using requests, so that must be the source of the delay.
Is there something about how LiveServerTestCase works that I'm not understanding here?
Could it be that the LiveServerTestCase server can only handle a single request at a time? So it hangs because it can't deal with a request-from-within-a-request?
The source says it will "handle one request at a time", but then again it says "without blocking", so that's ambiguous...
I think you're going to be best off dropping LiveServerTestCase and just rolling your own test runner. You can use setUp to spin up runserver
in a separate process, and tearDown
to reset the database (manage.py flush
?). If you want to use a test database, you could use a different settings.py, or just move the "real" database out of the way for the duration of the test...
The request is hanging after the test is complete because you're making the request via the requests
library and not the official test client described here.
You don't even need to do this though, it makes more sense to test the API directly and not spin up a web server through Django.
This is a decription of LiveServerTestCase
from the documentation here
LiveServerTestCase
launches a live Django server in the background on
setup, and shuts it down on teardown. This allows the use of automated
test clients such as, for example, the Selenium client, to execute a
series of functional tests inside a browser and simulate a real user’s
actions.
There's no need to even initalise the Django application if you want to test the API itself.
One method for testing I like to follow for problems like this is the component integration methodology, sort of described on Wikipedia here.
In this example we would test the Django application (the front end) separately from the service layer (the API). You may still use the API's when testing the front end, but the separation exists to define how you write the tests.
Since the API is a Flask
application, I would use Flasks built in testing tools described here.
The API has nothing to do with Django, yes it is consumed by a Django application, and that application has a hard dependency on that API, but you're wanting to specifically test the API itself.
To aid in UI testing, you could use the API as part of your test fixture/setUp
routine to save yourself from using the UI to add any test data needed for execution. However, if you're wanting to test the API itself then doing it through the Django client is not going to work due to the issue mentioned above.