Add automatic testing for model str method

This adds dynamic tests which check if the overwritten __str__ method of
a Model is not the same as the default __str__ method
parent 6a86c28a
......@@ -351,10 +351,11 @@ class MemberGroupMembership(models.Model, metaclass=ModelTranslateMeta):
self.member.save()
def __str__(self):
return "{} membership of {} since {}, until {}".format(self.member,
self.group,
self.since,
self.until)
return _("{member} membership of {group} "
"since {since}, until {until}").format(member=self.member,
group=self.group,
since=self.since,
until=self.until)
class Meta:
verbose_name = _('group membership')
......
......@@ -164,3 +164,6 @@ class Slide(models.Model, metaclass=ModelTranslateMeta):
"""Is this slide currently visible"""
return ((self.until is None or self.until > timezone.now()) and
(self.since is None or self.since <= timezone.now()))
def __str__(self):
return self.title
......@@ -72,6 +72,9 @@ class Newsletter(models.Model, metaclass=ModelTranslateMeta):
("send_newsletter", "Can send newsletter"),
)
def __str__(self):
return self.title
class NewsletterContent(models.Model, metaclass=ModelTranslateMeta):
"""Describes one piece of basic content of a newsletter"""
......@@ -115,6 +118,9 @@ class NewsletterContent(models.Model, metaclass=ModelTranslateMeta):
class Meta:
order_with_respect_to = 'newsletter'
def __str__(self):
return self.title
class NewsletterItem(NewsletterContent):
"""Describes one piece of text content of a newsletter"""
......
This diff was suppressed by a .gitattributes entry.
......@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-02-20 21:27+0100\n"
"PO-Revision-Date: 2019-02-20 21:27+0100\n"
"POT-Creation-Date: 2019-03-02 16:50+0100\n"
"PO-Revision-Date: 2019-03-02 16:51+0100\n"
"Last-Translator: Thom Wiggers <thom@thomwiggers.nl>\n"
"Language-Team: \n"
"Language: nl\n"
......@@ -133,6 +133,11 @@ msgstr "betalingen"
msgid "Process payments"
msgstr "Verwerk betalingen"
#: models.py
#, python-brace-format
msgid "Payment of {amount}"
msgstr "Betaling van {amount}"
#: templates/admin/payments/change_form.html templates/payments/widget.html
msgid "Process (cash payment)"
msgstr "Verwerk (contant)"
......
......@@ -90,3 +90,6 @@ class Payment(models.Model):
permissions = (
('process_payments', _("Process payments")),
)
def __str__(self):
return _("Payment of {amount}").format(amount=self.amount)
This diff was suppressed by a .gitattributes entry.
......@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-10-05 15:13+0200\n"
"PO-Revision-Date: 2018-03-21 20:03+0100\n"
"POT-Creation-Date: 2019-03-02 16:51+0100\n"
"PO-Revision-Date: 2019-03-02 16:51+0100\n"
"Last-Translator: Thom Wiggers <thom@thomwiggers.nl>\n"
"Language-Team: \n"
"Language: nl\n"
......@@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.0.6\n"
"X-Generator: Poedit 2.2.1\n"
#: admin.py
#, python-brace-format
......@@ -27,8 +27,7 @@ msgstr "<strong><a href=\"{link}\">Bestellingen</a></strong>"
msgid "Either specify a member or a name"
msgstr "Specificeer een lid of vul een naam in"
#: apps.py templates/pizzas/add_order.html templates/pizzas/index.html
#: templates/pizzas/orders.html templates/pizzas/overview.html
#: apps.py
msgid "Pizzas"
msgstr "Pizza's"
......@@ -40,6 +39,10 @@ msgstr "Bestel vanaf"
msgid "Order until"
msgstr "Bestel tot"
#: models.py
msgid "Send an order notification"
msgstr "Stuur een bestellingsherinnering"
#: models.py
msgid "This event cannot overlap with {}."
msgstr "Dit evenement kan niet overlappen met {}."
......@@ -68,10 +71,20 @@ msgstr "Bestel beperkte producten"
msgid "Use this for non-members"
msgstr "Vul dit in voor niet-leden"
#: models.py
#, python-brace-format
msgid "Order by {member_name}: {product}"
msgstr "Bestelling van {member_name}: {product}"
#: templates/pizzas/add_order.html
msgid "Add order"
msgstr "Nieuwe bestelling toevoegen"
#: templates/pizzas/add_order.html templates/pizzas/index.html
#: templates/pizzas/orders.html templates/pizzas/overview.html
msgid "pizzas"
msgstr "pizza's"
#: templates/pizzas/add_order.html
#, python-format
msgid "Add order for %(title)s"
......@@ -109,7 +122,7 @@ msgstr "Bestel eten voor %(title)s"
msgid "There is no current event for which you can order food"
msgstr "Er is nu geen evenement waar je eten voor kunt bestellen"
#: templates/pizzas/index.html
#: templates/pizzas/index.html templates/pizzas/orders.html
msgid "All products"
msgstr "Alle producten"
......@@ -194,10 +207,6 @@ msgstr "Weet je zeker dat je de bestelling aan wilt passen?"
msgid "Orders for %(title)s"
msgstr "Bestellingen voor %(title)s"
#: templates/pizzas/orders.html
msgid "Add a new order"
msgstr "Nieuwe bestelling toevoegen"
#: templates/pizzas/orders.html
msgid "Overview"
msgstr "Overzicht"
......@@ -206,11 +215,11 @@ msgstr "Overzicht"
msgid "Paid"
msgstr "Betaald"
#: templates/pizzas/orders.html templates/pizzas/overview.html
#: templates/pizzas/orders.html
msgid "Yes"
msgstr "Ja"
#: templates/pizzas/orders.html templates/pizzas/overview.html
#: templates/pizzas/orders.html
msgid "No"
msgstr "Nee"
......
......@@ -209,3 +209,9 @@ class Order(models.Model):
class Meta:
unique_together = ('pizza_event', 'member',)
def __str__(self):
return _("Order by {member_name}: {product}").format(
member_name=self.member_name,
product=self.product
)
This diff was suppressed by a .gitattributes entry.
......@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-08-19 15:30+0200\n"
"PO-Revision-Date: 2018-08-19 15:30+0200\n"
"POT-Creation-Date: 2019-03-02 16:51+0100\n"
"PO-Revision-Date: 2019-03-02 16:52+0100\n"
"Last-Translator: Thom Wiggers <thom@thomwiggers.nl>\n"
"Language-Team: \n"
"Language: nl\n"
......@@ -11,7 +11,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.1.1\n"
"X-Generator: Poedit 2.2.1\n"
#: admin.py
msgid "Enable selected devices"
......@@ -33,6 +33,10 @@ msgstr "Pushnotificaties"
msgid "name"
msgstr "naam"
#: models.py
msgid "description"
msgstr "beschrijving"
#: models.py
msgid "registration token"
msgstr "registratie token"
......@@ -54,32 +58,9 @@ msgid "language"
msgstr "taal"
#: models.py
msgid "General"
msgstr "Algemeen"
#: models.py
msgid "Pizza"
msgstr "Pizza"
#: models.py
msgid "Events"
msgstr "Evenementen"
#: models.py
msgid "Newsletter"
msgstr "Nieuwsbrief"
#: models.py
msgid "Messages from partners"
msgstr "Berichten van partners"
#: models.py
msgid "Photos"
msgstr "Foto's"
#: models.py
msgid "Board"
msgstr "Bestuur"
#, python-brace-format
msgid "{user}s {device_type} device"
msgstr "{user}s {device_type} apparaat"
#: models.py
msgid "title"
......@@ -89,6 +70,10 @@ msgstr "titel"
msgid "body"
msgstr "bericht"
#: models.py
msgid "url"
msgstr "url"
#: models.py
msgid "category"
msgstr "categorie"
......
......@@ -71,6 +71,11 @@ class Device(models.Model):
class Meta:
unique_together = ('registration_id', 'user',)
def __str__(self):
return _(
"{user}s {device_type} device"
).format(user=self.user, device_type=self.type)
class MessageManager(models.Manager):
"""Returns manual messages only"""
......
This diff was suppressed by a .gitattributes entry.
......@@ -107,7 +107,7 @@ class Entry(models.Model):
return self.renewal.__str__()
except Renewal.DoesNotExist:
pass
return super().__str__()
return _("Registration entry")
class Meta:
verbose_name = _('entry')
......
from unittest import mock
from django.contrib.auth import get_user_model
from django.core import mail
from django.core.exceptions import ValidationError
......@@ -42,8 +40,7 @@ class EntryTest(TestCase):
membership_type=Membership.MEMBER,
)
@mock.patch('django.db.models.Model.__str__')
def test_str(self, str_mock):
def test_str(self):
entry = Entry(registration=self.registration)
self.assertEqual(str(entry), '{} {} ({})'.format(
self.registration.first_name, self.registration.last_name,
......@@ -54,11 +51,6 @@ class EntryTest(TestCase):
self.member.first_name, self.member.last_name,
self.member.email))
str_mock.return_value = 'return str'
entry = Entry()
str(entry)
str_mock.assert_called_once_with()
class RegistrationTest(TestCase):
"""Tests registrations"""
......
from django.apps import apps
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.test import TestCase
def create_models_test_class(classname):
"""
Create the class for all the model __str__ tests.
This class is created dynamically with the type(name, bases, dict)
function, it includes test functions to test all the models in the project.
:param classname: The name to use for the created class
:return: An instance of the TestCase class with generated tests
"""
def create_model_test_function(name, test_model):
"""Create a test function that tests database model test_model."""
def str_function_is_overwritten_for(self):
"""Check if the test_model overrides __str__ by comparing the
implementation to the super class version."""
instance = test_model()
try:
# the implemented __str__ method should be different from the
# __str__ function in the parent class (Model)
self.assertNotEqual(
str(instance),
models.Model.__str__(instance)
)
except (ObjectDoesNotExist, AttributeError, KeyError, TypeError):
# if the __str__ method relies on any fields which were not
# instantiated, it throws a derivative of ObjectDoesNotExist,
# or one of the other errors which means it is different from
# the parent class implementation
pass
# the testing framework uses qualname to print the method name and
# its class
str_function_is_overwritten_for.__qualname__ = f'{classname}.{name}'
str_function_is_overwritten_for.__name__ = name
return str_function_is_overwritten_for
tests = dict()
# django keeps track of the models it knows of, and we can request that
# here by default these are only the models implemented by the project
for model in apps.get_models():
funcname = f'test_str_method_overwritten_for_{model.__name__}'
tests[funcname] = create_model_test_function(funcname, model)
# type() is the class constructor, it's arguments are
# name: name of the class
# bases: classes the new class inherits from
# dict: attributes (which includes methods) of this class
return type(classname, (TestCase,), tests)
# create the class to be picked up by the django test runner
ModelsTest = create_models_test_class('ModelsTest')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment