Coverage for website/thaliawebsite/tests/test_models.py: 100.00%

24 statements  

« prev     ^ index     » next       coverage.py v7.6.7, created at 2025-08-14 10:31 +0000

1from django.apps import apps 

2from django.core.exceptions import ObjectDoesNotExist 

3from django.db import models 

4from django.test import TestCase 

5 

6# Third-party apps whose models haven't implemented __str__ overrides. 

7_EXCLUDED_APPS = { 

8 "django_drf_filepond", 

9 "thumbnails", 

10 "otp_static", 

11 "otp_totp", 

12} 

13 

14 

15def create_models_test_class(classname): 

16 """Create the class for all the model __str__ tests. 

17 

18 This class is created dynamically with the type(name, bases, dict) 

19 function, it includes test functions to test all the models in the project. 

20 

21 :param classname: The name to use for the created class 

22 :return: An instance of the TestCase class with generated tests 

23 """ 

24 

25 def create_model_test_function(name, test_model): 

26 """Create a test function that tests database model test_model.""" 

27 

28 def str_function_is_overwritten_for(self): 

29 """Check if the test_model overrides __str__. 

30 

31 Compares the implementation to the super class version. 

32 """ 

33 instance = test_model() 

34 try: 

35 # the implemented __str__ method should be different from the 

36 # __str__ function in the parent class (Model) 

37 self.assertNotEqual(str(instance), models.Model.__str__(instance)) 

38 except (ObjectDoesNotExist, AttributeError, KeyError, TypeError): 

39 # if the __str__ method relies on any fields which were not 

40 # instantiated, it throws a derivative of ObjectDoesNotExist, 

41 # or one of the other errors which means it is different from 

42 # the parent class implementation 

43 pass 

44 

45 # the testing framework uses qualname to print the method name and 

46 # its class 

47 str_function_is_overwritten_for.__qualname__ = f"{classname}.{name}" 

48 str_function_is_overwritten_for.__name__ = name 

49 return str_function_is_overwritten_for 

50 

51 tests = {} 

52 # django keeps track of the models it knows of, and we can request that 

53 # here by default these are only the models implemented by the project 

54 for model in apps.get_models(): 

55 if model._meta.app_label in _EXCLUDED_APPS: 

56 continue 

57 funcname = f"test_str_method_overwritten_for_{model.__name__}" 

58 tests[funcname] = create_model_test_function(funcname, model) 

59 

60 # type() is the class constructor, it's arguments are 

61 # name: name of the class 

62 # bases: classes the new class inherits from 

63 # dict: attributes (which includes methods) of this class 

64 return type(classname, (TestCase,), tests) 

65 

66 

67# create the class to be picked up by the django test runner 

68ModelsTest = create_models_test_class("ModelsTest")