Reputation: 4391
Am trying to do a unit test for a view that returns a message when some input is duplicated in the database.it gives me the error TypeError: 'NoneType' object is not subscriptable
Here is the view
@login_required
def worker_create(request):
worker_create_form = WorkerCreateForm(request.POST)
if request.method == 'POST':
if worker_create_form.is_valid():
form = worker_create_form.save(commit=False)
phone = form.phone
check_phone = Worker.objects.filter(phone=phone)
if check_phone.count() != 0:
messages.error(request, 'رقم الهاتف مستخدم من قبل')
else:
form.save()
return redirect('worker_list')
else:
worker_create_form = WorkerCreateForm(request.POST)
context = {
'worker_create_form': worker_create_form,
}
return render(request, 'erp_system/worker/create.html', context)
and here are the tests I've created for it
class WorkerCreateTest(TestCase):
def setUp(self):
User.objects.create_user(username='test_user', email='[email protected]', password='test_password')
branch = Branch.objects.create(name='test branch')
Worker.objects.create(name="ay btngan ", phone='01207199086', branch=branch)
def test_get_request_unauthenticated(self):
response = self.client.get(reverse('worker_create'))
url = reverse('worker_create')
self.assertRedirects(response, '/login/?next=' + url)
def test_get_request_authenticated(self):
self.client.login(username='test_user', password='test_password')
response = self.client.get(reverse('worker_create'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed('erp_system/worker/create.html')
def test_post_request_empty_data(self):
self.client.login(username='test_user', password='test_password')
response = self.client.post(reverse('worker_create'), {})
self.assertFormError(response, 'worker_create_form', 'name', 'This field is required.')
self.assertFormError(response, 'worker_create_form', 'phone', 'This field is required.')
self.assertFormError(response, 'worker_create_form', 'branch', 'This field is required.')
def test_post_request_invalid_data(self):
self.client.login(username='test_user', password='test_password')
branch = Branch.objects.create(name='test again ')
name = 'just a name'
for i in range(300):
name += 'h'
response = self.client.post(reverse('worker_create'),
{'name': name, 'phone': '01207199086', 'branch': branch.id})
self.assertEqual(response.status_code, 200)
def test_post_request_duplicated_phone(self):
self.client.login(username='test_user', password='test_password')
branch = Branch.objects.create(name='test again ')
response = self.client.post(reverse('worker_create'),
{'name': 'test worker', 'phone': '01207199086', 'branch': branch.id})
print(response)
messages = list(response.context['messages'])
self.assertEqual(len(messages), 1)
self.assertEqual(str(messages[0]), 'رقم الهاتف مستخدم من قبل')
def test_post_request_valid_data(self):
self.client.login(username='test_user', password='test_password')
branch = Branch.objects.create(name='test branch1234')
name = 'new valid name'
response = self.client.post(reverse('worker_create'),
{'name': name, 'branch': branch.id, 'phone': '0151951115'})
self.assertEqual(response.status_code, 302)
Important
I noticed when I added print(response)
that it gives me HttpResponseRedirect
not just HttpResponse
what means there is no context given. Why it using redirect in here!?
Upvotes: 1
Views: 1354
Reputation: 476729
In your test test_post_request_duplicated_phone
, you make a POST request to the worker_create
, and you expect to retrieve an error, because there exists already a record for the given phone
.
The documentation on tests [Django-doc] however mentions that:
A
TestCase
, on the other hand, does not truncate tables after a test. Instead, it encloses the test code in a database transaction that is rolled back at the end of the test. This guarantees that the rollback at the end of the test restores the database to its initial state.
So that means that, unless you implement some "tricks" to prevent this, the side-effects that one test has (on the database) will be gone when you enter a second test. This makes sense, since reordering the tests should not result in a different outcome.
You can however create such Worker
object in your test in advance, and thus make sure that the test will indeed error:
def test_post_request_duplicated_phone(self):
self.client.login(username='test_user', password='test_password')
branch = Branch.objects.create(name='test again ')
Worker.objects.create(name=" just a name ", phone='01207199086', branch=branch)
response = self.client.post(reverse('worker_create'),
{'name': 'test worker', 'phone': '01207199086', 'branch': branch.id})
print(response)
messages = list(response.context['messages'])
self.assertEqual(len(messages), 1)
self.assertEqual(str(messages[0]), 'رقم الهاتف مستخدم من قبل')
Upvotes: 1