Is it possible to sub-parametrize pytest parameters values? - django

I'm working on a DRF (REST API) project and I'm using pytest. Quite often I find myself writing almost identical test parameters and I've been wondering if there's something I'm missing. I haven't read the entire pytest docs, although I definitely did read the entire django docs chapter on tests (not very helpful in my case) and I've now spent a few hours trying to find a solution. Let's assume I have a view like this:
from rest_framework import generics
from myapp.permissions import IsStaff, IsAdmin
class MessagesListView(generics.ListAPIView):
permission_classes = [IsStaff | IsAdmin]
# ...
(Note: just for the example please assume that user with IsAdmin permission does not necessarily have IsStaff permission; this is not the point of the question.)
And for this view I wrote a test:
import pytest
from rest_framework.reverse import reverse_lazy
from pytest_lazy_fixture import lazy_fixture
class TestMessagesListViewPermissions:
def get_response(self, client):
url = reverse_lazy("api:messages-list")
return client.get(url)
#pytest.mark.parametrize(
argnames=["client", "expected_response_status"],
argvalues=[
pytest.param(
"anonymous_client",
status.HTTP_403_FORBIDDEN,
),
pytest.param(
"authenticated_client",
status.HTTP_403_FORBIDDEN,
),
pytest.param(
"staff_client",
status.HTTP_200_OK,
),
pytest.param(
"admin_client",
status.HTTP_200_OK,
),
],
)
def test__permissions(self, client, expected_response_status):
# WHEN
response = self.get_response(client)
# THEN
assert response.status_code == expected_response_status
And there are 4 different client values, but 1+2nd and 3+4th result in the same response status code. As I said, it's a simplified example, but what if there are 10 parameters? What I'd like to be able to do is something like this:
#pytest.mark.parametrize(
argnames=["client", "expected_response_status"],
argvalues=[
pytest.param(
ParamList["anonymous_client", "authenticated_client"],
status.HTTP_403_FORBIDDEN,
),
pytest.param(
ParamList["staff_client", "admin_client"],
status.HTTP_200_OK,
),
],
)
Is there any pytest feature I'm missing or a plugin that makes this possible?

Have you considered pytest-subtests?
Here is a long discussion about its benefits and drawbacks: https://blog.ganssle.io/articles/2020/04/subtests-in-python.html

Related

How to Use Viewsets and Serializers in pytest==7.0.1 Parametrize in Testing djangorestframework==3.13.1 get_serializer() and get_permission()?

I am using a Django Project Template from here. I am testing my serializers and permission in every viewset my app has. I want to use parametrize from pytest to reduce the lines I need to write tests to each serializers and viewset. I have 10 serializers and viewset that I need to test which has a pattern as shown bellow.
test_drf_viewsets.py
#pytest.mark.parametrize(
("app_url", "app_viewset", "serializer"),
[
(
"api:mv-signup-list",
viewset.UserSignUpMaterializedViewSet,
serializers.UserSignUpMaterializedViewSerializer,
),
(
"api:mv-total-list",
viewset.TotalMaterializedViewSet,
serializers.TotalMaterializedViewSerializer,
),
],
)
def test_get_serializer(
self,
admin_user: User,
app_url: str,
app_viewset,
serializer,
rf: RequestFactory,
):
viewsets = app_viewset
request = rf.get(reverse(app_url))
request.user = admin_user
viewsets.request = Request(request)
viewsets.format_kwarg = None
assert isinstance(viewsets.get_serializer(), serializer)
However, when I run the code above, it shows this error
TypeError: GenericAPIView.get_serializer() missing 1 required positional argument: 'self'
The code presented above is omitted for brevity.
I found a minimal solution that works for my use case.
Instead of using these:
assert isinstance(viewsets.get_serializer(), serializer)
Change it to these:
assert viewsets.serializer_class == serializer
Same with get_permission:
assert viewsets.permission_classes[0] == IsAuthenticated
The code above works when these are changed.

Testing Django Rest Framework: how to test hyperlink relations?

I'm trying to create a true unit test for a customized DjangoRestFramework Hyperlinked related field. But I cannot seem to get around this error:
django.core.exceptions.ImproperlyConfigured: Could not resolve URL for hyperlinked relationship using view name "relatedtestmodel-detail". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.
And here is the unit test, stripped down to simplify the example:
from django.conf.urls import url
from django.test import TestCase, override_settings
from api_tests.models import APITestModel, RelatedTestModel
from api_tests.serializers import APITestModelSerializer
def dummy_view(request, pk):
pass
urlpatterns = [
url(r'/path/is/irrelevant/', dummy_view, name='relatedtestmodel-detail')
]
#override_settings(ROOT_URLCONF='tests.test_relations')
class HyperlinkedRelatedFieldTestCase(TestCase):
def setUp(self):
self.parent = APITestModel.objects.create()
self.child = RelatedTestModel.objects.create(parent=self.parent)
assert self.child.parent.id == self.parent.id
def test_to_internal_value_correct_error_message(self):
queryset = APITestModel.objects.all()
serializer = APITestModelSerializer(queryset, many=True, context={'request': None})
expected = [{'foo': 'bar'}]
self.assertEqual(serializer.data, expected)
I more or less lifted the test from https://github.com/encode/django-rest-framework/blob/master/tests/test_relations_hyperlink.py, because I figured who knows best how to unit test DRF than the makers of DRF? But as it stands, my test refuses to run. The error is raised during the test, when I attempt to access serializer.data for the assert.
Notice in particular that I override the settings with a custom urlpatterns (which is this same file, hence the urlpatterns at the top). So I don't understand why DRF thinks that url name doesn't exist - I can clearly see that my url conf in fact has ONLY that view name! I've even gone so far as to edit my actual URL conf and replace it with the single, named, dummy url pattern shown here, and removedthe settings override, just to be sure that it wasn't that the override_settings simply wasn't working, but even then I get the same error.
To my eye, the dummy url pattern is exactly the same as how DRF did it in their tests. Anyone have any ideas what is going on?
A bit more requested context:
api_tests.models:
from django.db import models
class APITestModel(models.Model):
pass
class RelatedTestModel(models.Model):
parent = models.ForeignKey(
APITestModel,
related_name='children',
related_query_name='child'
)
I do not have access to the traceback at this time, but I can confirm it did not pass through any of my code - it was all isolated to the DjangoRestFramework code, basically exclusively relations.py
Preamble
A few things this question is lacking
No definition of APITestModelSerializer
RelatedTestModel is not used in the test and therefore irrelevant for the example
No error stacktrace
No "useful" expected dict for the asserts
APITestModel has no fields so it can't be serialized (your test shouldn't even have run)
Minor things but still relevant
You are creating specific instances of APITestModel and RelatedTestModel in the setUp but in the test you serialize all instances of APITestModel
The line assert self.child.parent.id == self.parent.id should not be in the setUp. It should be in a separate test
My changes
I deleted all irrelevant information for this question mentioned above
I added an integer field to APITestModel
I changed the urlpatterns element from url(...) to path(...)
I added a regex to the relative path
The serializer is a subclass of HyperlinkedModelSerializer and includes fields "url" and "year"
My project and app urls.py files are the "stock" ones (not shown here) to emphasize that this test resolves the path in isolation.
Changed #override_settings(ROOT_URLCONF='tests.test_relations') to #override_settings(ROOT_URLCONF=__name__)
Code
models.py
from django.db import models
class APITestModel(models.Model):
year = models.IntegerField(null=False)
serializers.py
from rest_framework import serializers
from api.models import APITestModel
class APITestModelSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = APITestModel
fields = ["url", "year"]
test_serializers.py
from django.test import TestCase, override_settings
from django.urls import path
from api.models import APITestModel
from api.serializers import APITestModelSerializer
urlpatterns = [
path('whateveryouwant/<int:pk>/', lambda request: None, name='apitestmodel-detail'),
]
#override_settings(ROOT_URLCONF=__name__)
class HyperlinkedRelatedFieldTestCase(TestCase):
def setUp(self):
# Populate db with APITestModel instances
_ = APITestModel.objects.create(year=1960)
_ = APITestModel.objects.create(year=1961)
_ = APITestModel.objects.create(year=1962)
def test_to_internal_value_correct_error_message(self):
queryset = APITestModel.objects.all()
serializer = APITestModelSerializer(queryset, many=True, context={'request': None})
expected = [
{'url': '/whateveryouwant/1/', 'year': 1960},
{'url': '/whateveryouwant/2/', 'year': 1961},
{'url': '/whateveryouwant/3/', 'year': 1962},
]
self.assertEqual(serializer.data, expected)
The other files in the project are the default ones created automatically by django + djangorestframework.
For future readers, I created a github project with this working code and can be found here: https://github.com/Alechan/drf_test_hyperlink_relations

With drf-yasg, how can I support multiple serializers in the Response?

With a response from my drf just containing the data given by a single serializer, we can implement it as:
#swagger_auto_schema(
operation_id='ID example',
operation_description="Description example.",
responses={status.HTTP_200_OK: Serializer4ModelA(many=True)},
)
Which works fantastic, but with some requests constructing a dictionary, where two or three of the keys correspond to different serializers, e.g.
response = {
"a": serializer_data_for_model_a,
"b": serializer_data_for_model_b,
"c": serializer_data_for_model_c
}
How can we describe that in the auto schema? I've tried a few different approaches, mostly similar to the following:
#swagger_auto_schema(
operation_id='ID example',
operation_description="Description example.",
responses={status.HTTP_200_OK: openapi.Response(
description='response description',
schema=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'a': Serializer4ModelA(many=True),
'b': Serializer4ModelB(many=True),
'c': Serializer4ModelC(many=True)
})
)}
)
But always fails when loading the documentation, with flex saying:
"/usr/local/lib/python3.6/site-packages/flex/utils.py", line 125, in
get_type_for_value raise ValueError("Unable to identify type of
{0}".format(repr(value)))
ValueError: Unable to identify type of
Serializer4ModelA(many=True):
I've read the documentation over and over again, and scoured over github for an example, but I couldn't find an example or anyone doing this. So my question is how to successfully manually define a schema for a response that contains different serializers for different keys in the returned response?
What I usually do is to create another serializer (just so that drf-yasg can generate the docs).
For example if I have an endpoint that returns:
{
"results": [..list of serialized results with serializer X...]
}
I create a second serializer:
class Y(serializers.Serializer):
results = X(many=True)
and use Y serializer in the swagger_auto_schema decorator.
I ended up being able to do it, although probably not the most elegant solution but it does work.
My drf has a custom app-label format, so all my apps are in a folder, and let's call this folder apps.
In my question, for a serializer, we can replace Serializer4ModelA in the properties section of the openapi.Schema with a custom function, lets say get_serializer(Serializer4ModelA()).
So my idea was to basically construct the schema myself by getting the information automatically and automatically constructing the properties dictionary. It's very hacky, but useful for me because in my documentation I also want to pass in the serializers for Dynamodb, so I made a very similar function for Dynamodb serializers.
I only just made it, and it works, but obviously needs more attention to cover all fields in the field mapping, better dealing with SerializerMethodFields.
But none the less, it is a solution that works but is not generic, tweaks and stuff will have to be made depending on your particular project.
I implemented the function roughly as follows:
from drf_yasg import openapi
from drf_yasg.inspectors import SwaggerAutoSchema
from drf_yasg.utils import swagger_auto_schema
from drf_yasg.inspectors import FieldInspector
from drf_yasg.utils import swagger_serializer_method
import rest_framework
rest_framework_openapi_field_mapping = {
"ListField": openapi.TYPE_ARRAY,
"CharField": openapi.TYPE_STRING,
"BooleanField": openapi.TYPE_BOOLEAN,
"FloatField": openapi.TYPE_NUMBER,
"DateTimeField": openapi.TYPE_STRING,
"IntegerField": openapi.TYPE_INTEGER,
"SerializerMethodField": openapi.TYPE_STRING
}
def parse_rest_framework_field(field):
rest_framework_field_type = field.split("(")[0]
openapi_field_type =
rest_framework_openapi_field_mapping[rest_framework_field_type]
if "help_text=" in field:
field_description = field.split("help_text='")[-1].split("'")[0]
else:
field_description = None
return openapi.Schema(type=openapi_field_type, description=field_description)
def parse_serializer(serializer):
properties = {}
for k,v in serializer.get_fields().items():
if v.__module__ == "rest_framework.fields":
properties[k] = parse_rest_framework_field(str(v))
elif v.__module__.startswith("apps."):
serializer = str(v).strip().split("(")[0]
exec(f"from {v.__module__} import {serializer}")
eval_serializer = eval(f"{serializer}()")
properties[k] = openapi.Schema(type=openapi.TYPE_OBJECT, properties=parse_serializer(eval_serializer))
else:
pass
return properties
def get_serializer(serializer, description):
""" Needs to return openapi.Schema() """
properties = parse_serializer(serializer)
return_openapi_schema = openapi.Schema( type=openapi.TYPE_OBJECT, properties=properties, description=description)
return return_openapi_schema
I faced this problem and was looking if there is another way than my initial solution (same as how #Hernan explained it) but found none. The code of drf_yasg.openapi.Schema (drf_yasg==1.20.0) showed that it doesn't accept any serializer object. So as already said by #Hernan, the way around this is to have an additional serializer and define there the nested child serializers. Then, pass it to either the swagger_auto_schema.responses directly or through an openapi.Response.schema (as below):
from django.urls import path
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import serializers, status, views
class Serializer4ModelA(serializers.Serializer):
dog = serializers.CharField(label="My dog is a good boy")
class Serializer4ModelB(serializers.Serializer):
perro = serializers.CharField(label="Mi perro es un buen chico")
hund = serializers.CharField(label="Mein Hund ist ein guter Junge")
aso = serializers.CharField(label="Ang aso ko ay mabait na bata")
class Serializer4ModelC(serializers.Serializer):
eey = serializers.CharField(label="Eygaygu waa wiil fiican")
class SampleResponseSerializer(serializers.Serializer):
a = Serializer4ModelA(many=True)
b = Serializer4ModelB(many=True)
c = Serializer4ModelC(many=True)
class SampleView(views.APIView):
#swagger_auto_schema(
responses={
status.HTTP_200_OK: openapi.Response(
description="response description",
schema=SampleResponseSerializer,
)
}
)
def get(self, request):
pass
urlpatterns = [
path("sample/", SampleView.as_view()),
]
Output:

mocking a method on django model using post_save signal

So here's something I'm trying to figure out. I've got a method that is triggered by post_save
for this "Story" model. Works fine. What I need to do is figure out how to mock out the test, so I can fake the call and make assertions on my returns. I think I need to patch it somehow, but I've tried a couple different ways without much success. Best i can get is a object instance, but it ignores values I pass in.
I've commented in my test where my confusion lies. Any help would be welcome.
Here's my test:
from django.test import TestCase
from django.test.client import Client
from marketing.blog.models import Post, Tag
from unittest.mock import patch, Mock
class BlogTestCase(TestCase):
fixtures = [
'auth-test.json',
'blog-test.json',
]
def setUp(self):
self.client = Client()
def test_list(self):
# verify that we can load the list page
r = self.client.get('/blog/')
self.assertEqual(r.status_code, 200)
self.assertContains(r, "<h1>The Latest from Our Blog</h1>")
self.assertContains(r, 'Simple JavaScript Date Formatting')
self.assertContains(r, 'Page 1 of 2')
# loading a page out of range should redirect to last page
r = self.client.get('/blog/5/', follow=True)
self.assertEqual(r.redirect_chain, [
('http://testserver/blog/2/', 302)
])
self.assertContains(r, 'Page 2 of 2')
# verify that unpublished posts are not displayed
with patch('requests') as mock_requests:
# my futile attempt at mocking.
# creates <MagicMock> object but not able to call return_values
mock_requests.post.return_value = mock_response = Mock()
# this doesn't get to the magic mock object. Why?
mock_response.status_code = 201
p = Post.objects.get(id=5)
p.published = False
# post_save signal runs here and requests is called.
# Needs to be mocked.
p.save()
r = self.client.get('/blog/')
self.assertNotContains(r, 'Simple JavaScript Date Formatting')
Here's the model:
from django.db import models
from django.conf import settings
from django.db.models import signals
import requests
def update_console(sender, instance, raw, created, **kwargs):
# ignoring raw so that test fixture data can load without
# hitting this method.
if not raw:
update = instance
json_obj = {
'author': {
'alias': 'the_dude',
'token': 'the_dude'
},
'text': update.description,
}
headers = {'content-type': 'application/json'}
path = 'http://testserver.com:80/content/add/'
request = requests(path, 'POST',
json_obj, headers=headers,
)
if request.status_code < 299:
story_id = request.json().get('id')
if story_id:
# disconnect and reconnect signal so
# we don't enter recursion-land
signals.post_save.disconnect(
update_console,
sender = Story, )
update.story_id = story_id
update.save()
signals.post_save.connect(
update_console,
sender = Story, )
else:
raise AttributeError('Error Saving to console, '+ request.text)
class Story(models.Model):
"""Lets tell a story"""
story_id = models.CharField(
blank=True,
max_length=10,
help_text="This maps to the id of the post"
)
slug = models.SlugField(
unique=True,
help_text="This is used in URL and in code references.",
)
description = models.TextField(
help_text='2-3 short paragraphs about the story.',
)
def __str__(self):
return self.short_headline
# add/update this record as a custom update in console
signals.post_save.connect(update_console, sender = Story)
You need to patch requests in the module where it is actually used, i.e.
with patch('path.to.your.models.requests') as mock_requests:
mock_requests.return_value.status_code = 200
mock_requests.return_value.json.return_value = {'id': story_id'}
...
The documentation offers more detailed explanations on where to patch:
patch works by (temporarily) changing the object that a name points to with another one. There can be many names pointing to any individual object, so for patching to work you must ensure that you patch the name used by the system under test.
The basic principle is that you patch where an object is looked up, which is not necessarily the same place as where it is defined.
Here, you need to patch the name requests inside the models module, hence the need to provide its full path.

Why don't my Django unittests know that MessageMiddleware is installed?

I'm working on a Django project and am writing unittests for it. However, in a test, when I try and log a user in, I get this error:
MessageFailure: You cannot add messages without installing django.contrib.messages.middleware.MessageMiddleware
Logging in on the actual site works fine -- and a login message is displayed using the MessageMiddleware.
In my tests, if I do this:
from django.conf import settings
print settings.MIDDLEWARE_CLASSES
Then it outputs this:
('django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware')
Which appears to show the MessageMiddleware is installed when tests are run.
Is there an obvious step I'm missing?
UPDATE
After suggestions below, it does look like it's a settings thing.
I currently have settings/__init__.py like this:
try:
from settings.development import *
except ImportError:
pass
and settings/defaults.py containing most of the standard settings (including MIDDLEWARE_CLASSES). And then settings.development.py overrides some of those defaults like this:
from defaults import *
DEBUG = True
# etc
It looks like my dev site itself works fine, using the development settings. But although the tests seem to load the settings OK (both defaults and development) settings.DEBUG is set to False. I don't know why, or whether that's the cause of the problem.
Django 1.4 has a expected behavior when you create the request with RequestFactory that can trigger this error.
To resolve this issue, create your request with RequestFactory and do this:
from django.contrib.messages.storage.fallback import FallbackStorage
setattr(request, 'session', 'session')
messages = FallbackStorage(request)
setattr(request, '_messages', messages)
Works for me!
A way to solve this quite elegant is to mock the messages module using mock
Say you have a class based view named FooView in app named myapp
from django.contrib import messages
from django.views.generic import TemplateView
class FooView(TemplateView):
def post(self, request, *args, **kwargs):
...
messages.add_message(request, messages.SUCCESS, '\o/ Profit \o/')
...
You now can test it with
def test_successful_post(self):
mock_messages = patch('myapp.views.FooView.messages').start()
mock_messages.SUCCESS = success = 'super duper'
request = self.rf.post('/', {})
view = FooView.as_view()
response = view(request)
msg = _(u'\o/ Profit \o/')
mock_messages.add_message.assert_called_with(request, success, msg)
In my case (django 1.8) this problem occurs in when unit-test calls signal handler for user_logged_in signal, looks like messages app has not been called, i.e. request._messages is not yet set. This fails:
from django.contrib.auth.signals import user_logged_in
...
#receiver(user_logged_in)
def user_logged_in_handler(sender, user, request, **kwargs):
...
messages.warning(request, "user has logged in")
the same call to messages.warning in normal view function (that is called after) works without any issues.
A workaround I based on one of the suggestions from https://code.djangoproject.com/ticket/17971, use fail_silently argument only in signal handler function, i.e. this solved my problem:
messages.warning(request, "user has logged in",
fail_silently=True )
Do you only have one settings.py?
Tests create custom (tests) database. Maybe you have no messages there or something... Maybe you need setUp() fixtures or something?
Need more info to answer properly.
Why not simply do something like ? You sure run tests in debug mode right?
# settings.py
DEBUG = True
from django.conf import settings
# where message is sent:
if not settings.DEBUG:
# send your message ...
This builds on Tarsis Azevedo's answer by creating a MessagingRequest helper class below.
Given say a KittenAdmin I'd want to get 100% test coverage for:
from django.contrib import admin, messages
class KittenAdmin(admin.ModelAdmin):
def warm_fuzzy_method(self, request):
messages.warning(request, 'Can I haz cheezburger?')
I created a MessagingRequest helper class to use in say a test_helpers.py file:
from django.contrib.messages.storage.fallback import FallbackStorage
from django.http import HttpRequest
class MessagingRequest(HttpRequest):
session = 'session'
def __init__(self):
super(MessagingRequest, self).__init__()
self._messages = FallbackStorage(self)
def get_messages(self):
return getattr(self._messages, '_queued_messages')
def get_message_strings(self):
return [str(m) for m in self.get_messages()]
Then in a standard Django tests.py:
from django.contrib.admin.sites import AdminSite
from django.test import TestCase
from cats.kitten.admin import KittenAdmin
from cats.kitten.models import Kitten
from cats.kitten.test_helpers import MessagingRequest
class KittenAdminTest(TestCase):
def test_kitten_admin_message(self):
admin = KittenAdmin(model=Kitten, admin_site=AdminSite())
expect = ['Can I haz cheezburger?']
request = MessagingRequest()
admin.warm_fuzzy_method(request)
self.assertEqual(request.get_message_strings(), expect)
Results:
coverage run --include='cats/kitten/*' manage.py test; coverage report -m
Creating test database for alias 'default'...
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Destroying test database for alias 'default'...
Name Stmts Miss Cover Missing
----------------------------------------------------------------------
cats/kitten/__init__.py 0 0 100%
cats/kitten/admin.py 4 0 100%
cats/kitten/migrations/0001_initial.py 5 0 100%
cats/kitten/migrations/__init__.py 0 0 100%
cats/kitten/models.py 3 0 100%
cats/kitten/test_helpers.py 11 0 100%
cats/kitten/tests.py 12 0 100%
----------------------------------------------------------------------
TOTAL 35 0 100%
This happened to me in the login_callback signal receiver function when called from a unit test, and the way around the problem was:
from django.contrib.messages.storage import default_storage
#receiver(user_logged_in)
def login_callback(sender, user, request, **kwargs):
if not hasattr(request, '_messages'): # fails for tests
request._messages = default_storage(request)
Django 2.0.x
I found when I had a problem patching messages the solution was to patch the module from within the class under test (obsolete Django version BTW, YMMV). Pseudocode follows.
my_module.py:
from django.contrib import messages
class MyClass:
def help(self):
messages.add_message(self.request, messages.ERROR, "Foobar!")
test_my_module.py:
from unittest import patch, MagicMock
from my_module import MyClass
class TestMyClass(TestCase):
def test_help(self):
with patch("my_module.messages") as mock_messages:
mock_messages.add_message = MagicMock()
MyClass().help() # shouldn't complain about middleware
If you're seeing a problem in your Middleware, then you're not doing "Unit Test". Unit tests test a unit of functionality. If you interact with other parts of your system, you're making something called "integration" testing.
You should try to write better tests, and this kind of problems shouldn't arise. Try RequestFactory. ;)
def test_some_view(self):
factory = RequestFactory()
user = get_mock_user()
request = factory.get("/my/view")
request.user = user
response = my_view(request)
self.asssertEqual(status_code, 200)