Happy with test cases

main
Thu Trang Pham 2020-11-06 01:10:14 -08:00
parent 081aec4821
commit c6a44f6426
5 changed files with 116 additions and 47 deletions

2
Makefile 100644
View File

@ -0,0 +1,2 @@
run:
./tests/manage.py runserver

View File

@ -52,7 +52,7 @@ class AdminConfirmMixin:
def changeform_view(self, request, object_id=None, form_url="", extra_context=None): def changeform_view(self, request, object_id=None, form_url="", extra_context=None):
if request.method == "POST": if request.method == "POST":
if (not object_id and "_confirm_add" in request.POST) or (object_id and "_confirm_change"): if (not object_id and "_confirm_add" in request.POST) or (object_id and "_confirm_change" in request.POST):
return self._change_confirmation_view(request, object_id, form_url, extra_context) return self._change_confirmation_view(request, object_id, form_url, extra_context)
extra_context = { extra_context = {
@ -68,6 +68,7 @@ class AdminConfirmMixin:
TO_FIELD_VAR, request.GET.get(TO_FIELD_VAR) TO_FIELD_VAR, request.GET.get(TO_FIELD_VAR)
) )
if to_field and not self.to_field_allowed(request, to_field): if to_field and not self.to_field_allowed(request, to_field):
print("OKAY WHAT")
raise DisallowedModelAdminToField( raise DisallowedModelAdminToField(
"The field %s cannot be referenced." % to_field "The field %s cannot be referenced." % to_field
) )
@ -115,8 +116,8 @@ class AdminConfirmMixin:
if field.has_changed(initial_value, new_value) and initial_value != new_value: if field.has_changed(initial_value, new_value) and initial_value != new_value:
changed_data[name] = [initial_value, new_value] changed_data[name] = [initial_value, new_value]
changed_confirmation_fields = set(self.get_confirmation_fields(request, obj)) & set(changed_data.keys()) changed_confirmation_fields = set(self.get_confirmation_fields(
self.message_user(request, changed_confirmation_fields) request, obj)) & set(changed_data.keys())
if not bool(changed_confirmation_fields): if not bool(changed_confirmation_fields):
# No confirmation required for changed fields, continue to save # No confirmation required for changed fields, continue to save
return super()._changeform_view(request, object_id, form_url, extra_context) return super()._changeform_view(request, object_id, form_url, extra_context)

View File

@ -1,69 +1,135 @@
from unittest import mock from django.test import TestCase, RequestFactory
from requests import Request from django.contrib.auth.models import User
from django.test import TestCase
from django.contrib.admin.sites import AdminSite from django.contrib.admin.sites import AdminSite
from tests.market.admin import ItemAdmin, InventoryAdmin, ShopAdmin from tests.market.admin import ItemAdmin
from tests.market.models import Item from tests.market.models import Item, Inventory
from tests.factories import ItemFactory, InventoryFactory, ShopFactory from django.urls import reverse
from tests.factories import ItemFactory, ShopFactory
class TestAdminConfirmMixin(TestCase): class TestAdminConfirmMixin(TestCase):
@mock.patch('django.contrib.admin.options.changeform_view') @classmethod
def test_add_without_confirm(self, mock_super): def setUpTestData(cls):
ItemAdmin.confirm_add = None cls.superuser = User.objects.create_superuser(
admin = ItemAdmin(Item, AdminSite()) username='super', email='super@email.org', password='pass')
request = Request('POST', 'url', data={'name': 'name', 'price': 2.0, 'currency': Item.VALID_CURRENCIES[0]})
confirmation_template = admin.render_change_confirmation(request, context={}).template_name def setUp(self):
# object_id = None for adding self.client.force_login(self.superuser)
actual_template = admin.changeform_view(request).template_name self.factory = RequestFactory()
mock_super.assert_called_once()
self.assertNotEqual(confirmation_template, actual_template)
def test_change_with_no_options(self): def test_get_add_without_confirm_add(self):
response = self.client.get(reverse('admin:market_item_add'))
self.assertFalse(response.context_data.get('confirm_add'))
self.assertNotIn('_confirm_add', response.rendered_content)
def test_get_add_with_confirm_add(self):
response = self.client.get(reverse('admin:market_inventory_add'))
self.assertTrue(response.context_data.get('confirm_add'))
self.assertIn('_confirm_add', response.rendered_content)
def test_with_confirm_change(self): def test_get_change_without_confirm_change(self):
pass response = self.client.get(reverse('admin:market_shop_add'))
self.assertFalse(response.context_data.get('confirm_change'))
self.assertNotIn('_confirm_change', response.rendered_content)
def test_with_confirm_add(self): def test_get_change_with_confirm_change(self):
pass response = self.client.get(reverse('admin:market_inventory_add'))
self.assertTrue(response.context_data.get('confirm_change'))
self.assertIn('_confirm_change', response.rendered_content)
def test_post_add_without_confirm_add(self):
data = {'name': 'name', 'price': 2.0,
'currency': Item.VALID_CURRENCIES[0]}
response = self.client.post(reverse('admin:market_item_add'), data)
# Redirects to item changelist and item is added
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, '/admin/market/item/')
self.assertEqual(Item.objects.count(), 1)
def test_post_add_with_confirm_add(self):
item = ItemFactory()
shop = ShopFactory()
data = {'shop': shop.id, 'item': item.id,
'quantity': 5, '_confirm_add': True}
response = self.client.post(
reverse('admin:market_inventory_add'), data)
# Ensure not redirected (confirmation page does not redirect)
self.assertEqual(response.status_code, 200)
expected_templates = [
'admin/market/inventory/change_confirmation.html',
'admin/market/change_confirmation.html',
'admin/change_confirmation.html'
]
self.assertEqual(response.template_name, expected_templates)
form_data = {'shop': str(shop.id), 'item': str(
item.id), 'quantity': str(5)}
self.assertEqual(
response.context_data['form_data'], form_data)
for k, v in form_data.items():
self.assertIn(
f'<input type="hidden" name="{ k }" value="{ v }">', response.rendered_content)
# Should not have been added yet
self.assertEqual(Inventory.objects.count(), 0)
def test_post_change_with_confirm_change(self):
item = ItemFactory(name='item')
data = {'name': 'name', 'price': 2.0,
'currency': Item.VALID_CURRENCIES[0], '_confirm_change': True}
response = self.client.post(
f'/admin/market/item/{item.id}/change/', data)
# Ensure not redirected (confirmation page does not redirect)
self.assertEqual(response.status_code, 200)
expected_templates = [
'admin/market/item/change_confirmation.html',
'admin/market/change_confirmation.html',
'admin/change_confirmation.html'
]
self.assertEqual(response.template_name, expected_templates)
form_data = {'name': 'name', 'price': str(2.0),
'currency': Item.VALID_CURRENCIES[0][0]}
self.assertEqual(
response.context_data['form_data'], form_data)
for k, v in form_data.items():
self.assertIn(
f'<input type="hidden" name="{ k }" value="{ v }">', response.rendered_content)
# Hasn't changed item yet
item.refresh_from_db()
self.assertEqual(item.name, 'item')
def test_post_change_without_confirm_change(self):
shop = ShopFactory(name='bob')
data = {'name': 'sally'}
response = self.client.post(
f'/admin/market/shop/{shop.id}/change/', data)
# Redirects to changelist
print(response)
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, '/admin/market/shop/')
# Shop has changed
shop.refresh_from_db()
self.assertEqual(shop.name, 'sally')
def test_get_confirmation_fields_should_default_if_not_set(self): def test_get_confirmation_fields_should_default_if_not_set(self):
expected_fields = [f.name for f in Item._meta.fields if f.name != 'id'] expected_fields = [f.name for f in Item._meta.fields if f.name != 'id']
ItemAdmin.confirmation_fields = None ItemAdmin.confirmation_fields = None
admin = ItemAdmin(Item, AdminSite()) admin = ItemAdmin(Item, AdminSite())
actual_fields = admin.get_confirmation_fields(Request('GET', 'url')) actual_fields = admin.get_confirmation_fields(self.factory.request())
self.assertEqual(expected_fields, actual_fields) self.assertEqual(expected_fields, actual_fields)
def test_get_confirmation_fields_if_set(self): def test_get_confirmation_fields_if_set(self):
expected_fields = ['name', 'currency'] expected_fields = ['name', 'currency']
ItemAdmin.confirmation_fields = expected_fields ItemAdmin.confirmation_fields = expected_fields
admin = ItemAdmin(Item, AdminSite()) admin = ItemAdmin(Item, AdminSite())
actual_fields = admin.get_confirmation_fields(Request('GET', 'url')) actual_fields = admin.get_confirmation_fields(self.factory.request())
self.assertEqual(expected_fields, actual_fields) self.assertEqual(expected_fields, actual_fields)
def test_custom_template(self): def test_custom_template(self):
expected_template = 'my_custom_template.html' expected_template = 'my_custom_template.html'
ItemAdmin.confirmation_template = expected_template ItemAdmin.confirmation_template = expected_template
admin = ItemAdmin(Item, AdminSite()) admin = ItemAdmin(Item, AdminSite())
actual_template = admin.render_change_confirmation(Request('POST', 'url'), context={}).template_name actual_template = admin.render_change_confirmation(
self.factory.request(), context={}).template_name
self.assertEqual(expected_template, actual_template) self.assertEqual(expected_template, actual_template)
class TestAdminConfirmMixinConfirmChange(TestCase):
pass
class TestAdminConfirmMixinConfirmAdd(TestCase):
pass
class TestAdminConfirmMixinConfirmChangeWithFields(TestCase):
pass
class TestAdminConfirmMixinConfirmChangeWithFields(TestCase):
pass

View File

@ -1,6 +1,6 @@
import factory import factory
from random import choice from random import choice, randint
from tests.market.models import Item, Shop, Inventory from tests.market.models import Item, Shop, Inventory
@ -10,7 +10,7 @@ class ItemFactory(factory.django.DjangoModelFactory):
model = Item model = Item
name = factory.Faker('name') name = factory.Faker('name')
price = factory.Faker('price') price = factory.LazyAttribute(lambda _: randint(5, 500))
currency = factory.LazyAttribute(lambda _: choice(Item.VALID_CURRENCIES)) currency = factory.LazyAttribute(lambda _: choice(Item.VALID_CURRENCIES))

View File

@ -23,4 +23,4 @@ class ShopAdmin(AdminConfirmMixin, admin.ModelAdmin):
admin.site.register(Item, ItemAdmin) admin.site.register(Item, ItemAdmin)
admin.site.register(Inventory, InventoryAdmin) admin.site.register(Inventory, InventoryAdmin)
admin.site.register(Shop, ShopAdmin) admin.site.register(Shop, ShopAdmin)