from django.db import models from django.contrib.auth.models import User from django.core.exceptions import FieldDoesNotExist from django.test import TestCase # Creating a test user class ModelTestCase: ''' Base class for ModelTests ''' model = None model_name = None def setUp(self): if not self.model._meta.abstract: self.object = self.model.objects.get(id=1) self.model_name = self.model.__name__ def assertField(self, field_name, field_class, must_have={}, must_not_have={}): ''' Tests if a field exists under the given name and if the field is of the right type. Also checks if the field has the given must_have attributes and does not have any of the must_not_have attributes. If you dont care about the value of the attribute you can just set it to something that fullfills value == False (i.e. '' or 0) ''' try: field = self.model._meta.get_field(field_name) except FieldDoesNotExist: self.fail( 'Expecting %s to have a field named \'%s\'' % ( self.model_name, field_name ) ) self.assertEqual( type(field), field_class, msg='Expecting type of %s.%s to be %s' % ( self.model_name, field_name, field_class.__name__ ) ) for key, value in must_have.items(): if value: self.assertEqual(getattr(field, key), value, msg='Expeting %s.%s.%s to be \'%s\'' % ( self.model_name, field_name, key, value ) ) else: self.assertTrue(hasattr(field, key), msg='Expeting %s.%s to have \'%s\'' % ( self.model_name, field_name, key ) ) for key, value in must_not_have.items(): if value: self.assertTrue(getattr(field, key) != value, msg='Expeting %s.%s.%s to not be \'%s\'' % ( self.model_name, field_name, key, value ) ) else: self.assertFalse(hasattr(field, value), msg='Expeting %s.%s to not have \'%s\'' % ( self.model_name, field_name, key ) ) return field def assertCharField(self, field_name, min_length, max_length, must_have={}, must_hot_have={}): ''' Tests if the given field is a char field and if its max_length is in min_length and max_legth ''' field = self.assertField( field_name, models.CharField, must_have, must_hot_have) self.assertTrue( field.max_length in range(min_length, max_length), msg='Expeting %s.%s field max_length to be in the range of %d and %d' % ( self.model_name, field_name, min_length, max_length ) ) def assertFloatField(self, field_name, min_value=None, max_value=None, must_have={}, must_hot_have={}): ''' Tests if the field is a floatfield. If min_value and/or max_value are passed, the validators of the field are also checked. The validator list of the field should look like [MinValueValidator, MayValueValidator], if both values are passed, [MinValueValidator] if only min_value is passed, [MaxValueValidator] if only max_value is passed ''' field = self.assertField( field_name, models.FloatField, must_have, must_hot_have) if min_value: self.assertTrue( len(field.validators) >= 1, msg='Expecting the first valiator of %s.%s to check the minimum' % ( self.model_name, field_name ) ) self.assertEqual( field.validators[0].limit_value, min_value, msg='Expecting the min value of %s.%s min to be at least %d' % ( self.model_name, field_name, min_value ) ) if max_value: index = 0 if min_value: index += 1 self.assertTrue( len(field.validators) >= index+1, msg='Expecting the second valiator of %s.%s to check the maximum' % ( self.model_name, field_name ) ) self.assertEqual( field.validators[1].limit_value, max_value, msg='Expecting the max value of %s.%s min to be at most %d' % ( self.model_name, field_name, max_value ) ) class SubmittableTestCase(ModelTestCase): related_name = None nullable = False def test_submitted_when(self): submitted_when = self.assertField( 'submitted_when', models.DateTimeField, must_have={'auto_now_add': True} ) def test_submitted_by(self): submitted_by = self.assertField('submitted_by', models.ForeignKey) if self.related_name: self.assertEqual( submitted_by.remote_field.related_name, self.related_name) if self.nullable: self.assertTrue(submitted_by.null,) self.assertTrue(submitted_by.blank) self.assertEqual( submitted_by.remote_field.on_delete, models.SET_NULL)