I have a class based view inheriting from FormView with an overridden form_valid() method that I would like to test.
As you can see, form_valid() is required to access the CustomUser model which is wrapped with a try and except.
What I am trying to do is raise an exception whenever create_user is called, but I am having no success.
The CustomUser has been created in the usual way via a CustomUserManager with a create_user method.
CustomUser = get_user_model()
class SignUpView(FormView):
template_name = 'accounts/signup.html'
form_class = SignUpForm
def form_valid(self, form):
try:
self.user = CustomUser.objects.filter(email=form.cleaned_data['email']).first()
if not self.user:
self.user = CustomUser.objects.create_user(email=form.cleaned_data['email'],
full_name=form.cleaned_data['full_name'],
password=form.cleaned_data['password'],
is_verified=False
)
else:
if self.user.is_verified:
self.send_reminder()
return super().form_valid(form)
self.send_code()
except:
messages.error(self.request, _('Something went wrong, please try to register again'))
return redirect(reverse('accounts:signup'))
return super().form_valid(form)
What I have tried:
def test_database_fail(self):
with patch.object(CustomUserManager, 'create_user') as mock_method:
mock_method.side_effect = Exception(ValueError)
view = SignUpView.as_view()
url = reverse('accounts:signup')
data = {'email': '[email protected]', 'full_name': 'Test Tester', 'password': 'Abnm1234'}
request = self.factory.post(url, data)
request.session = {}
request.messages = {}
response = view(request)
and ..
def test_database_fail(self):
CustomUser = Mock()
CustomUser.objects.create_user.side_effect = CustomUser.ValueError
view = SignUpView.as_view()
url = reverse('accounts:signup')
data = {'email': '[email protected]', 'full_name': 'Test Tester', 'password': 'Abnm1234'}
request = self.factory.post(url, data)
request.session = {}
request.messages = {}
response = view(request)
In both cases no exception is triggered.
My question is, how can I raise an exception whenever create_user is called using mock?
You need to write the whole test under mock.patch
context manager. Otherwise once with
statement is finished, mock doesn't work anymore and has no effect. Try this:
def test_database_fail(self):
with patch.object(CustomUserManager, 'create_user') as mock_method:
mock_method.side_effect = Exception(ValueError)
view = SignUpView.as_view()
url = reverse('accounts:signup')
data = {'email': '[email protected]', 'full_name': 'Test Tester', 'password': 'Abnm1234'}
request = self.factory.post(url, data)
request.session = {}
request.messages = {}
response = view(request)
Also note that you can specify side_effect directly in patch.object
method:
with patch.object(CustomUserManager, 'create_user', side_effect=Exception):
# rest of your code