I am trying to switch from using Django Test Client to RequestFactory to speed up my tests. However, requests generated by RequestFactory do not supply proper kwargs
to views.
Example: this is my view
class SomeView(View):
def get(self, request, *args, **kwargs):
return JsonResponse({'your kwargs': str(kwargs)})
with urlconf
url(r'^some_view/(?P<some_kwarg>[\-0-9a-fA-F]+)/$',
views.SomeView.as_view(),
name='some_view'),
and two tests:
def test_different_kwargs():
c = Client()
response = c.get(
reverse('bots:some_view',
kwargs={'some_kwarg': '12345'}),
)
print('\n\nResponse for TestClient: ', response.content.decode())
rf = RequestFactory()
request = rf.get(
reverse('bots:some_view',
kwargs={'some_kwarg': '12345'}),
)
response = SomeView.as_view()(request)
print('\n\nResponse for RequestFactory: ', response.content.decode())
What they produce is:
Response for TestClient: {"your kwargs": "{'some_kwarg': '12345'}"}
Response for RequestFactory: {"your kwargs": "{}"}
So, what's the point of RequestFactory
if it loses url kwargs? Or is there a way to put them into the view somehow?
EDIT 2020-03-07: As gain I more experience in testing, I updated my answer to remove confusion around functional testing and I added some advises.
There are two aspects to your answer.
Quick answer: how to put the kwargs
in the view? You need to change your code to this:
def test_different_kwargs():
kwargs={'some_kwarg': '12345'}
url = reverse('bots:some_view', kwargs=kwargs)
c = Client()
response = c.get(url)
print('\n\nResponse for TestClient: ', response.content.decode())
rf = RequestFactory()
request = rf.get(url)
response = SomeView.as_view()(request, **kwargs)
print('\n\nResponse for RequestFactory: ', response.content.decode())
Long answer:
Then the difference between RequestFactory
and Client
:
It has been developed a bit here: Django test RequestFactory vs Client
but I would like to complete it a bit.
In terms of functionality Client
handle the whole stack used to process the response including middlewares and url resolutions (url matching and parameters extraction). On the other side RequestFactory
, just build a request object, leaving the responsibility to the user to add the proper attributes and to call the appropriate view functions or view methods.
Hence the call to ClassView.as_view()(request, *args, **kwargs)
in the second case.
In terms of testing, Client
is focused on integration testing (you will test that all the different parts fit together: middlewares, class-based/function view, template, templatetags), it's the end-to-end mechanism that you are testing here.
Client -> { UrlResolver -> Middleware -> View -> Middlewares -> TemplateResponse } -> Tests
Using RequestFactory
you can focus on testing smaller parts, a class-based view method, a function view, a middleware method etc. In that sense RequestFactory
is more related to unit testing.
See Request Factory Reference
If you are interest in unit tests and mocking methods, there is not much literature on this but you can look at this article (Testing Django Views in Isolation)[https://matthewdaly.co.uk/blog/2015/08/02/testing-django-views-in-isolation/].
In the end it all depends on how much you time can focus on testing. Integration/Functional/Unit testings have different advantages and drawbacks.
Advises (may be biased): If you develop a website, I advise the following:
Unit testing parts using RequestFactory
will take you more time and won't bring much benefits over using the Client
API.
Using Client
API you will be closer to how your website will be used and how it will behave.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With