functional_tests/test_list_item_validation.py增加一个测试方法
def test_cannot_add_duplicate_items(self):
#乔伊访问首页,新建一个清单
self.browser.get(self.live_server_url)
self.get_item_input_box().send_keys('Buy wellies')
self.get_item_input_box().send_keys(Keys.ENTER)
self.wait_for_row_in_list_table('1: Buy wellies')
#她不小心输入一个重复的待办事项
self.get_item_input_box().send_keys('Buy wellies')
self.get_item_input_box().send_keys(Keys.ENTER)
#她看到一条有帮助的错误消息
self.wait_for(lambda :self.assertEqual(
self.browser.find_element_by_css_selector('.has-error').text,
"You've already got this in your list"
))
python manage.py test functional_tests.test_list_item_validation
selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: .has-error
lists/tests/test_models.py
def test_duplicate_items_are_invalid(self):
list_ = List.objects.create()
Item.objects.create(list=list_,text='bla')
with self.assertRaises(ValidationError):
item = Item(list=list_,text='bla')
item.full_clean()
def test_CAN_save_same_item_to_diffrernt_lists(self):
list1 = List.objects.create()
list2 = List.objects.create()
Item.objects.create(list=list1,text='bla')
item = Item(list=list2,text='bla')
item.full_clean()
lists/models.py
class Item(models.Model):
text = models.TextField(default='')
list = models.ForeignKey(List, default=None)
class Meta:
unique_together = ('list', 'text')
单元测试通过。ps:如果失败的话,可能是唯一约束影响了查询排序,class Meta增加ordering = ('id',)
删除test_saving_and_retrieving_items,增加新方法,分为两个测试类
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author : Marvin King
# Date : 2019-02-22
from django.test import TestCase
from lists.models import Item, List
from django.core.exceptions import ValidationError
class ItemModelTest(TestCase):
def test_default_text(self):
item = Item()
self.assertEqual(item.text, '')
def test_item_is_related_to_list(self):
list_ = List.objects.create()
item = Item()
item.list = list_
item.save()
self.assertIn(item, list_.item_set.all())
def test_cannot_save_empty_list_items(self):
[...]
def test_duplicate_items_are_invalid(self):
[...]
def test_CAN_save_same_item_to_diffrernt_lists(self):
[...]
class ListModelTest(TestCase):
def test_get_absolute_url(self):
[...]
python manage.py makemigrations
Migrations for 'lists':
lists/migrations/0004_auto_20190225_1537.py
- Alter unique_together for item (1 constraint(s))
测试报错:IntegrityError
Ran 27 tests in 0.088s
OK
修改迁移文件名字:mv lists/migrations/0004_auto* lists/migrations/0004_list_item_unique_together.py
提交:git commit -am 'Implement duplicate item validation at model layer'
def test_duplicate_item_validation_errors_and_up_on_lists_page(self):
list1 = List.objects.create()
item1 = Item.objects.create(list=list1, text='textey')
response = self.client.post(
f'/lists/{list1.id}/',
data={'text': 'textey'}
)
expected_error = escape("You've already got this in your list")
self.assertContains(response, expected_error)
self.assertTemplateUsed(response, 'list.html')
self.assertEqual(Item.objects.all().count(), 1)
lists/tests/test_forms.py
class ExistingListItemFormTest(TestCase):
def test_form_renders_item_text_input(self):
list_ = List.objects.create()
form = ExistingListItemForm(for_list=list_)
self.assertIn('placeholder="Enter a to-do item"', form.as_p())
def test_form_validation_for_blank_items(self):
list_ = List.objects.create()
form = ExistingListItemForm(for_list=list_, data={'text': ''})
self.assertFalse(form.is_valid())
self.assertEqual(
form.errors['text'],
[EMPTY_ITEM_ERROR]
)
def test_form_validation_for_duplicate_items(self):
list_ = List.objects.create()
Item.objects.create(list=list_, text='no twins!')
form = ExistingListItemForm(for_list=list_, data={'text': 'no twins!'})
self.assertFalse(form.is_valid())
self.assertEqual(form.errors['text'], [DUPLICATE_ITEM_ERROR])
lists/forms.py
class ExistingListItemForm(forms.models.ModelForm):
def __init__(self, for_list, *args, **kwargs):
super().__init__(*args, **kwargs)
ValueError: ModelForm has no model class specified.
修改继续:
class ExistingListItemForm(ItemForm):
AssertionError: True is not false
Django在表单和模型中都会调用validate_unique.
class ExistingListItemForm(ItemForm):
def __init__(self, for_list, *args, **kwargs):
super().__init__(*args, **kwargs)
self.instance.list = for_list
def validate_unique(self):
try:
self.instance.validate_unique()
except ValidationError as e:
e.error_dict = {'text':[DUPLICATE_ITEM_ERROR]}
self._update_errors(e)
lists/tests/test_views.py清理常量测试
expected_error = escape(DUPLICATE_ITEM_ERROR)
修改
def test_displays_item_form(self): list_ = List.objects.create() response = self.client.get(f'/lists/{list_.id}/') self.assertIsInstance(response.context['form'], ExistingListItemForm) self.assertContains(response, 'name="text"')
def test_for_invalid_input_passes_form_to_template(self): response = self.post_invalid_input() self.assertIsInstance(response.context['form'], ExistingListItemForm)
单元测试:AssertionError:
修改视图:
def view_list(request, list_id): list_ = List.objects.get(id=list_id) form = ExistingListItemForm(for_list=list_) if request.method == 'POST': form = ExistingListItemForm(for_list=list_,data=request.POST) if form.is_valid(): form.save() return redirect(list_)
TypeError: save() missing 1 required positional argument: 'for_list'
lists/tests/test_models.py增加一个测试
def test_form_save(self): list_ = List.objects.create() form = ExistingListItemForm(for_list=list_,data={'text':'hi'}) new_item = form.save() self.assertEqual(new_item,Item.objects.all()[0])
lists/forms.py
def save(self): return forms.models.ModelForm.save(self)
python manage.py test lists
Ran 32 tests in 0.102s
OK
python manage.py test functional_tests
Ran 5 tests in 60.305s
OK
提交:git commit -am 'Finish 15th'