I didn't understand the way we should write tests for Django views. Because, my case felt different than others.
I have a view, let's say MyView, inherits from CreateView of Django generic class based views. But, in the background, I mean in the form_valid function, this view tries to connect to a remote server with a Python library, then fetches data according the input of the user, then process other details and saves the object if everything is OK, if not, it returns custom errors.
What should be my way to handle this kind of view so I can write a test?
(I can use something like that but it's not good to handle possible errors:
from django.test import Client
c = Client()
c.login(mydetails..)
y = c.post('/url/', {'my': 'data'})
It works, yes, but I only check the status code in this case. y.status_code
can't help, because Django returns 200 even if there is an error in the form.
To simplify testing framework in django, the test will simulate client request (like a user clicked on a link "url") this url is associated with a view which will handle the request and return a response to the user. for example in your test you will assert if the view renders the correct response and template. let suppose that we have a view for creating a blog, how might be tested? see the code below.
views.py
def createblog_view(request):
if request.method == 'POST':
form = BlogForm(request.POST)
if form.is_valid():
blog = form.save(commit=False)
blog.author = request.user # save the user who created the blog
blog.save()
return redirect(blog.get_absolute_url())
else:
form = BlogForm()
context = {'form': form}
return render(request, 'blog/createblog.html', context)
test.py
class BlogTest(TestCase):
def setUp(self):
# this user will be used to create the blog
self.user = User.objects.create_superuser(
'foo',
'[email protected]',
'password'
)
def test_create_blog(self): # create update and delete a blog
# log user in and user
self.client.login(username='foo', password='password')
# create new blog
# expected date from the user, you can put invalid data to test from validation
form_data = {
'title': 'new test blog',
'body': 'blog body'
}
form = BlogForm(data=blogform_data) # create form indstance
"""
simulate post request with self.client.post
/blog/createblog/ is the url associated with create_blog view
"""
response = self.client.post('/blog/createblog/', form_data)
# get number of created blog to be tested later
num_of_blogs = Blog.objects.all().count()
# get created blog
blog = Blog.objects.get(title=form_data['title'])
# test form validation
self.assertTrue(blogform.is_valid())
# test slugify method, if any
self.assertEqual(blog.slug, 'new-test-blog')
# test if the blog auther is the same logged in user
self.assertEqual(blog.author, self.user1)
# one blog created, test if this is true
self.assertEqual(num_of_blogs, 1)
# test redirection after blog created
self.assertRedirects(
createblog_response,
'/blog/new-test-blog/',
status_code=302,
target_status_code=200
)