Django Testing view template context - django

I'm trying to test the
return render(request, 'template.html', context)
and seem to be falling short. Is it not worth while testing this? Or if it is worth while testing this, how do I accomplish that?
view.py
def create_employee_profile(request):
name_form = EmployeeNameForm()
context = {'name_form':name_form}
return render(request,
'template_create_employee_profile.html',
context
)
I know the if: else: statements are missing. I didn't think they were relevant to the test.
test.py
# TEST: context({'name_form':name_form})
def test_CreateEmployeeProfileView_context(self):
name_form = EmployeeNameForm()
response = self.client.get(reverse(
'create_employee_profile'))
self.assertEquals(response.context['name_form'], name_form)
This got me the closest to success. Here's my error:
AssertionError: <Empl[27 chars]alid=False,
fields=(employee_choices;first_nam[20 chars]ame)> !=
<Empl[27 chars]alid=Unknown,
fields=(employee_choices;first_n[22 chars]ame)>
What about the detail view?
# TEST: context({'name':name})
def test_CustomerEmployeeProfileView_context(self):
name = CustomerEmployeeName.objects.get(pk=1)
response = self.client.get(
reverse('service:customer_employee_profile_detail', kwargs={'pk': 1}))
self.assertIsInstance(response.context['name'], name)
Got this error:
TypeError: isinstance() arg 2 must be a type or tuple of types

You are comparing two different instances of the EmployeeNameForm, which is why the assertion fails.
If you just want to test that the context variable is indeed a EmployeeNameForm then you can test it with assertIsInstance:
def test_CreateEmployeeProfileView_context(self):
response = self.client.get(reverse('create_employee_profile'))
self.assertIsInstance(response.context['name_form'], EmployeeNameForm)

Related

Pytest using a fixture to return value instead of function location

I want to perform pytest for the tenth_standard method inside HighSchool class:
Class HighSchool():
...
def tenth_standard(self):
return f"I-am-studying-in-{self.school}-at-{self.country}"
I want to use #pytest.fixture and #pytest.mark.parametrize to perform the pytest and my code is as below:
#pytest.fixture(scope="function")
def expected(request):
return f"I-am-studying-in-{school}-at-{country}"
#pytest.fixture(scope="function")
def school(request):
return request.param
#pytest.fixture(scope="function")
def country(request):
return request.param
#pytest.mark.parametrize("school", ["abcd", "efgh"], indirect=True)
#pytest.mark.parametrize("country", ["India", "Japan"], indirect=True)
def test_tenthstandard(school, country, expected):
b = HighSchool(school=school, country=country)
assert expected == b.tenth_standard()
When I run this, I get an AssertionError as below:
AssertionError: assert ('I-am-studying-in-<function school at 0x7f6b858a63a0>-at-<function country at '0x7f6b858a6280>) == 'I-am-studying-in-abcd-at-India'
I want to fix the expected fixture to return the values instead of function at XXX location. Could someone help me how to fix this?
Your expected fixture is not taking the parameters from the other fixtures, but just the fixture function, which is of course not what you want. You can just "derive" the expected fixture from the other fixtures, so it will be automatically parametrized with the same parameters:
#pytest.fixture
def school(request):
return request.param
#pytest.fixture
def country(request):
return request.param
#pytest.fixture
def expected(school, country):
return f"I-am-studying-in-{school}-at-{country}"
#pytest.mark.parametrize("school", ["abcd", "efgh"])
#pytest.mark.parametrize("country", ["India", "Japan"])
def test_tenthstandard(school, country, expected):
b = HighSchool(school=school, country=country)
assert expected == b.tenth_standard()
Note that it this case you can even skip the indirect=True part, as the expected fixture will already get the correct values.
As a side note: It is usually not a good idea to duplicate the application logic in the test, as is done here. This way bugs can easily propagate to the tests and not be found.
(though in this case it may only be due to a dumbed down example)

Passing a query into Django test

I want to test a view of my Django application.
def search(request):
query = request.GET.get('query')
query_lower = query.lower()
list_name = re.split("[- ’? ; , ' . : ' ' " " ]",query_lower)
stripped_query = [strip_accents(x) for x in list_name]
clean_query =[word for word in stripped_query if word not in stopwords]
match_list = []
for x in Product.objects.all():
match = 0
for y in clean_query:
if y in x.name or y in x.brand:
match += 1
if match == len(clean_query):
match_list.append(x.id)
else:
pass
if not query:
products_list= Product.objects.all()
else:
products_list = Product.objects.filter(id__in=match_list)
context = {
'products': products_list,
}
return render(request, 'finder/search.html', context)
I did create some products in my tests.py with setup and I want to test if I have a 200 status code if on of those products is searched:
def test_Search(self):
self.response = self.client.post(reverse(('finder:search'), {'query':'gazpacho'}))
self.assertEqual(self.response.status_code, 200)
I got a TypeError: unhashable type: 'dict'.
So, how I am supposed to pass my query into my test for it to be run?
Your view handles GET-parameters so the request itself is a GET-request.
In your test you are sending a post, which should be a get accordingly:
self.client.get(url, {'query': '...'})
Parameters are passed as the second argument for get()/post.
See more in the docs.
In your case most likely (without having the full trace of the error) your error is the way you are calling reverse() in your test.
The second argument passed to that function is urlconf. From the docs:
The urlconf argument is the URLconf module containing the URL patterns to use for reversing. By default, the root URLconf for the current thread is used.
Something like this?
class TestKlass(...):
def test_Search(self):
url = reverse('finder:search')
url_with_param = "{}?{}".format(url, 'query=gazpacho')
self.response = self.client.post(url_with_param)
self.assertEqual(self.response.status_code, 200)

error when rendering through get_object_or_404 django

The following code in my views.py throws an error if I don't use
else conditional statement specifying detail = None
Is there any better way to simplify the code without using else statement?
(just in case you don't understand the structure of my app, it only has detail, and list templates. list.html only shows the list of name record in model, and detail only shows the each name in detail page.)
def SimpleView(request, sluggy=None):
s = Simple.objects.all()
if sluggy:
detail = get_object_or_404(Simple, slug=sluggy)
else:
detail=None
return render(request,'simple_app/list.html',{'s':s,'d':detail})
def detaily(request,sluggy):
sluggys = get_object_or_404(Simple,slug=sluggy)
return render(request, 'simple_app/detail.html',{'sluggy':sluggys})
You can build up the context directly:
def SimpleView(request, sluggy=None):
context = {'s': Simple.objects.all()}
if sluggy:
context['d'] = get_object_or_404(Simple, slug=sluggy)
return render(request,'simple_app/list.html', context)
(Though please use more descriptive names for the template vars; there's no reason to use single characters.)
If you are really fixated on no using the else part, you should define the detail variable before the if statement. So if "if qualification" is not satisfied, "detail" variable in return statement will at-least have a defined value as None.
def SimpleView(request, sluggy=None):
s = Simple.objects.all()
detail=None
if sluggy:
detail = get_object_or_404(Simple, slug=sluggy)
return render(request,'simple_app/list.html',{'s':s,'d':detail})
def detaily(request,sluggy):
sluggys = get_object_or_404(Simple,slug=sluggy)
return render(request, 'simple_app/detail.html',{'sluggy':sluggys})

Django unit test views function - example

I'm newbie in Django tests. How to create Unit Test for this views function? My unit test function should import function from views? Please an example. This will help me to understand how it work
#maintainance_job
def time_to_end(request):
today = datetime.date.today()
datas = Data.objects.filter(start__lte=today,
other_date__gte=today)
for data in datas:
subject = _(u'Send email')
body = render_to_string('mail.txt',
{'data': data})
email = EmailMessage(subject, body,
'admin#admin.com',
[data.user.email])
email.send()
return HttpResponse('Done')
urls:
(r'^maintainance/jobs/time_to_end/$', 'content.views.time_to_end'),
There is a simpliest test for your case (place it in tests.py of a directory where is your view function):
from django.utils import unittest
from django.test.client import Client
class HttpTester( unittest.TestCase ):
def setUp( self ):
self._client = Client() # init a client for local access to pages of your site
def test_time_to_end( self ):
response = self._client.get( '/jobs/time_to_end/' )
# response = self._client.post( '/jobs/time_to_end/' ) - a 'POST' request
result = response.content
assert result != 'Done'
So, we use self._client to make 'get' and 'post' requests. Responses can be accessed by reading response.content (the full text of response) or by reading response.context if you use templates and want to access variables passing to the templates.
For example if your view normally must pass the dict with context variable 'result' to template:
{ 'result': "DONE" }
then you could check your result:
result = response.context[ 'result' ]
assert result != 'Done'
So, you wait your test will have the 'result' variable and it will be 'Done'. Otherwise you raise AssertionError (note assert statement).
If there is an exception then tests fails. AssertionError is an exception too.
More details - in the docs and in a book "Dive into Python".

Using named group to call function in view django

I don't know if something like this is possbile but I would like to call a function based on the named group value in the urls.py config.
This is what I have been looking at
url.py snippet
url(r'^ajax/ValidateLogin/(?P<funcname>\w{13})/$', Validate),
views.py snippet
def checkUsername(request):
user = User.objects.get(username=request.POST.get('username',''))
if user == None:
response = simplejson.dumps({'success':'True','validate':'True'})
else:
response = simplejson.dumps({'success':'True','validate':'False'})
return HttpResponse(response,content_type='application/javascript; charset=utf-8')
def Validate(request,funcname):
return funcname(request)
This just returns that unicode object isn't callable which I understand but how do I then convert it to call the view function check username? An example of url that should call this is ajax/ValidateLogin/checkUsername
Thanks
remote_function_calls = {
'check_username' : check_username,
}
def Validate(request, funcname):
try:
return remote_function_calls[funcname](request)
except KeyError:
response = http.HttpResponse("Invalid function")
response.status_code = 403
return response
Another method to define which functions are valid
def valid_function(request):
return http.HttpResponse("This function may be called remotely")
valid_function.remote_call_valid = True
def erase_everything_function(request):
world.delete()
valid_functions = dict([(k, v) for k, v in globals().iteritems() if
getattr(v, 'remote_call_valid', None) == True])
Use this:
def Validate(request,funcname):
return locals()[funcname](request)
Although this kind of thing is a bit of a security risk since any user can call any arbitrary function available to python by passing the right "funcname".