I am trying to understand how patching works and I am testing with pytest a Django View:
views.py
from django.contrib.auth.views import LoginView
class MyLoginView(LoginView):
pass
test_view.py
from django.test import RequestFactory
from .views import MyLoginView
rf = RequestFactory()
def test_login(rf):
request = rf.get(reverse('myapp:login'))
response = MyLoginView.as_view()(request)
assert response.status_code == 200
This fails because this View calls the database in order to get the current Site using the function get_current_site():
Failed: Database access not allowed
How can I mock get_current_site() to avoid the database hit?
An idea is to use a factory with pytest-factoryboy.
I managed to mock LoginView.get_context_data but I cannot go deeper:
from django.test import RequestFactory
from .views import MyLoginView
from django.contrib.sites.models import Site
from pytest_factoryboy import register
from unittest.mock import patch
rf = RequestFactory()
class SiteFactory(factory.Factory):
class Meta:
model = Site
register(SiteFactory)
def test_login_social(rf, site_factory):
request = rf.get(reverse('myapp:login'))
with patch(
# 'django.contrib.auth.views.LoginView.get_context_data', # This is wrong
'django.contrib.auth.views.get_current_site', # Solution: Patch where it is imported, this works!
return_value=site_factory(name='example.com'),
):
response = CommunityLoginView.as_view()(request)
assert response.status_code == 200
Edit
The solution is to patch the method beeing called, at the scope where it is imported:
with patch('django.contrib.auth.views.get_current_site')
Here an error occurs due to the context_data being a <class 'django.contrib.sites.models.Site'>
How would you do it?