716 lines
23 KiB
Python
716 lines
23 KiB
Python
"""
|
|
Author: Michel Peltriaux
|
|
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
|
Contact: michel.peltriaux@sgdnord.rlp.de
|
|
Created on: 26.10.21
|
|
|
|
"""
|
|
import datetime
|
|
import json
|
|
|
|
from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID, CODELIST_REGISTRATION_OFFICE_ID
|
|
from ema.models import Ema
|
|
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
|
|
from user.models import User, Team
|
|
from django.contrib.auth.models import Group
|
|
from django.contrib.gis.geos import MultiPolygon, Polygon
|
|
from django.core.exceptions import ObjectDoesNotExist
|
|
from django.test import TestCase, Client
|
|
from django.urls import reverse
|
|
|
|
from codelist.models import KonovaCode, KonovaCodeList
|
|
from compensation.models import Compensation, CompensationState, CompensationAction, EcoAccount, EcoAccountDeduction
|
|
from intervention.models import Legal, Responsibility, Intervention, Handler
|
|
from konova.management.commands.setup_data import GROUPS_DATA
|
|
from konova.models import Geometry, Deadline, DeadlineType
|
|
from konova.settings import DEFAULT_GROUP
|
|
from konova.utils.generators import generate_random_string
|
|
from user.models import UserActionLogEntry
|
|
|
|
|
|
class BaseTestCase(TestCase):
|
|
""" Provides reusable functionality for specialized test cases
|
|
|
|
"""
|
|
users = None
|
|
groups = None
|
|
superuser = None
|
|
user = None
|
|
intervention = None
|
|
compensation = None
|
|
eco_account = None
|
|
comp_state = None
|
|
comp_action = None
|
|
finished_deadline = None
|
|
codes = None
|
|
|
|
superuser_pw = "root"
|
|
user_pw = "root"
|
|
|
|
class Meta:
|
|
abstract = True
|
|
|
|
def setUp(self) -> None:
|
|
""" Setup data before each test run
|
|
|
|
Returns:
|
|
|
|
"""
|
|
super().setUp()
|
|
|
|
self.create_users()
|
|
self.create_groups()
|
|
self.handler = self.create_dummy_handler()
|
|
self.intervention = self.create_dummy_intervention()
|
|
self.compensation = self.create_dummy_compensation()
|
|
self.eco_account = self.create_dummy_eco_account()
|
|
self.ema = self.create_dummy_ema()
|
|
self.deduction = self.create_dummy_deduction()
|
|
self.create_dummy_states()
|
|
self.create_dummy_action()
|
|
self.codes = self.create_dummy_codes()
|
|
self.team = self.create_dummy_team()
|
|
self.finished_deadline = self.create_dummy_deadline()
|
|
|
|
# Set the default group as only group for the user
|
|
default_group = self.groups.get(name=DEFAULT_GROUP)
|
|
self.superuser.groups.set([default_group])
|
|
|
|
# Create fresh logged in client and a non-logged in client (anon) for each test
|
|
self.client_user = Client()
|
|
self.client_user.login(username=self.superuser.username, password=self.superuser_pw)
|
|
self.client_anon = Client()
|
|
|
|
|
|
def create_users(self):
|
|
# Create superuser and regular user
|
|
self.superuser = User.objects.create_superuser(
|
|
username="root",
|
|
email="root@root.com",
|
|
password=self.superuser_pw,
|
|
)
|
|
self.user = User.objects.create_user(
|
|
username="user1",
|
|
email="user@root.com",
|
|
password=self.user_pw
|
|
)
|
|
self.users = User.objects.all()
|
|
|
|
|
|
def create_groups(self):
|
|
# Create groups
|
|
for group_data in GROUPS_DATA:
|
|
name = group_data.get("name")
|
|
Group.objects.get_or_create(
|
|
name=name,
|
|
)
|
|
self.groups = Group.objects.all()
|
|
|
|
@staticmethod
|
|
def create_dummy_string(prefix: str = ""):
|
|
""" Create
|
|
|
|
Returns:
|
|
|
|
"""
|
|
return f"{prefix}{generate_random_string(3, True)}"
|
|
|
|
def create_dummy_document(self, DocumentModel, instance):
|
|
""" Creates a document db entry which can be used for tests
|
|
|
|
"""
|
|
doc = DocumentModel.objects.create(
|
|
title="TEST_doc",
|
|
comment="",
|
|
file=None,
|
|
date_of_creation="1970-01-01",
|
|
instance=instance,
|
|
)
|
|
return doc
|
|
|
|
def create_dummy_intervention(self):
|
|
""" Creates an intervention which can be used for tests
|
|
|
|
Returns:
|
|
|
|
"""
|
|
# Create dummy data
|
|
# Create log entry
|
|
action = UserActionLogEntry.get_created_action(self.superuser)
|
|
# Create legal data object (without M2M laws first)
|
|
legal_data = Legal.objects.create()
|
|
# Create responsible data object
|
|
responsibility_data = Responsibility.objects.create(
|
|
handler=self.handler
|
|
)
|
|
geometry = Geometry.objects.create()
|
|
# Finally create main object, holding the other objects
|
|
intervention = Intervention.objects.create(
|
|
identifier="TEST",
|
|
title="Test_title",
|
|
responsible=responsibility_data,
|
|
legal=legal_data,
|
|
created=action,
|
|
geometry=geometry,
|
|
comment="Test",
|
|
)
|
|
intervention.generate_access_token(make_unique=True)
|
|
return intervention
|
|
|
|
def create_dummy_compensation(self, interv: Intervention=None):
|
|
""" Creates a compensation which can be used for tests
|
|
|
|
Returns:
|
|
|
|
"""
|
|
if not interv:
|
|
if self.intervention is None:
|
|
interv = self.create_dummy_intervention()
|
|
else:
|
|
interv = self.intervention
|
|
# Create dummy data
|
|
# Create log entry
|
|
action = UserActionLogEntry.get_created_action(self.superuser)
|
|
geometry = Geometry.objects.create()
|
|
# Finally create main object, holding the other objects
|
|
compensation = Compensation.objects.create(
|
|
identifier="TEST",
|
|
title="Test_title",
|
|
intervention=interv,
|
|
created=action,
|
|
geometry=geometry,
|
|
comment="Test",
|
|
)
|
|
return compensation
|
|
|
|
def create_dummy_eco_account(self):
|
|
""" Creates an eco account which can be used for tests
|
|
|
|
Returns:
|
|
|
|
"""
|
|
# Create dummy data
|
|
# Create log entry
|
|
action = UserActionLogEntry.get_created_action(self.superuser)
|
|
geometry = Geometry.objects.create()
|
|
# Create responsible data object
|
|
lega_data = Legal.objects.create()
|
|
responsible_data = Responsibility.objects.create()
|
|
handler = self.handler
|
|
responsible_data.handler = handler
|
|
responsible_data.save()
|
|
|
|
identifier = EcoAccount().generate_new_identifier()
|
|
# Finally create main object, holding the other objects
|
|
eco_account = EcoAccount.objects.create(
|
|
identifier=identifier,
|
|
title="Test_title",
|
|
deductable_surface=500,
|
|
legal=lega_data,
|
|
responsible=responsible_data,
|
|
created=action,
|
|
geometry=geometry,
|
|
comment="Test",
|
|
)
|
|
return eco_account
|
|
|
|
def create_dummy_ema(self):
|
|
""" Creates an ema which can be used for tests
|
|
|
|
Returns:
|
|
|
|
"""
|
|
# Create dummy data
|
|
# Create log entry
|
|
action = UserActionLogEntry.get_created_action(self.superuser)
|
|
geometry = Geometry.objects.create()
|
|
# Create responsible data object
|
|
responsible_data = Responsibility.objects.create()
|
|
responsible_data.handler = self.handler
|
|
responsible_data.save()
|
|
# Finally create main object, holding the other objects
|
|
ema = Ema.objects.create(
|
|
identifier="TEST",
|
|
title="Test_title",
|
|
responsible=responsible_data,
|
|
created=action,
|
|
geometry=geometry,
|
|
comment="Test",
|
|
)
|
|
return ema
|
|
|
|
def create_dummy_deduction(self, acc: EcoAccount = None, interv: Intervention = None):
|
|
if not acc:
|
|
acc = self.create_dummy_eco_account()
|
|
if not interv:
|
|
interv = self.create_dummy_intervention()
|
|
|
|
return EcoAccountDeduction.objects.create(
|
|
account=acc,
|
|
intervention=interv,
|
|
surface=100,
|
|
)
|
|
|
|
def create_dummy_states(self):
|
|
""" Creates an intervention which can be used for tests
|
|
|
|
Returns:
|
|
|
|
"""
|
|
self.comp_state = CompensationState.objects.create(
|
|
surface=10.00,
|
|
biotope_type=None,
|
|
)
|
|
return self.comp_state
|
|
|
|
def create_dummy_action(self):
|
|
""" Creates an intervention which can be used for tests
|
|
|
|
Returns:
|
|
|
|
"""
|
|
self.comp_action = CompensationAction.objects.create(
|
|
amount=10
|
|
)
|
|
return self.comp_action
|
|
|
|
def create_dummy_codes(self):
|
|
""" Creates some dummy KonovaCodes which can be used for testing
|
|
|
|
Returns:
|
|
|
|
"""
|
|
codes = KonovaCode.objects.all()
|
|
if codes.count() == 0:
|
|
codes = KonovaCode.objects.bulk_create([
|
|
KonovaCode(id=1, is_selectable=True, is_archived=False, is_leaf=True, long_name="Test1"),
|
|
KonovaCode(id=2, is_selectable=True, is_archived=False, is_leaf=True, long_name="Test2"),
|
|
KonovaCode(id=3, is_selectable=True, is_archived=False, is_leaf=True, long_name="Test3"),
|
|
KonovaCode(id=4, is_selectable=True, is_archived=False, is_leaf=True, long_name="Test4"),
|
|
])
|
|
return codes
|
|
|
|
def create_dummy_team(self, name: str = None):
|
|
""" Creates a dummy team
|
|
|
|
Returns:
|
|
|
|
"""
|
|
if self.superuser is None:
|
|
self.create_users()
|
|
|
|
if not name:
|
|
name = "Testteam"
|
|
|
|
team = Team.objects.get_or_create(
|
|
name=name,
|
|
description="Testdescription",
|
|
)[0]
|
|
team.users.add(self.superuser)
|
|
|
|
return team
|
|
|
|
def create_dummy_deadline(self, type: DeadlineType = DeadlineType.FINISHED):
|
|
""" Creates a dummy deadline.
|
|
|
|
If type is not specified, it defaults to DeadlineType.FINISHED
|
|
|
|
Returns:
|
|
deadline (Deadline): A deadline
|
|
"""
|
|
deadline = Deadline.objects.create(
|
|
type=type,
|
|
date="1970-01-01"
|
|
)
|
|
return deadline
|
|
|
|
@staticmethod
|
|
def create_dummy_geometry() -> MultiPolygon:
|
|
""" Creates some geometry
|
|
|
|
Returns:
|
|
|
|
"""
|
|
polygon = Polygon.from_bbox((7.592449, 50.359385, 7.593382, 50.359874))
|
|
polygon.srid = 4326
|
|
polygon.transform(DEFAULT_SRID_RLP)
|
|
return MultiPolygon(polygon, srid=DEFAULT_SRID_RLP)
|
|
|
|
def create_geojson(self, geometry):
|
|
""" Creates a default structure including geojson from a geometry
|
|
|
|
Args:
|
|
geometry ():
|
|
|
|
Returns:
|
|
|
|
"""
|
|
geom_json = {
|
|
"features": [
|
|
{
|
|
"type": "Feature",
|
|
"geometry": json.loads(geometry.geojson),
|
|
}
|
|
]
|
|
}
|
|
geom_json = json.dumps(geom_json)
|
|
return geom_json
|
|
|
|
def create_dummy_handler(self) -> Handler:
|
|
""" Creates a Handler
|
|
|
|
Returns:
|
|
|
|
"""
|
|
handler = Handler.objects.get_or_create(
|
|
type=KonovaCode.objects.all().first(),
|
|
detail="Test handler"
|
|
)[0]
|
|
return handler
|
|
|
|
def fill_out_intervention(self, intervention: Intervention) -> Intervention:
|
|
""" Adds all required (dummy) data to an intervention
|
|
|
|
Args:
|
|
intervention (Intervention): The intervention which shall be filled out
|
|
|
|
Returns:
|
|
intervention (Intervention): The modified intervention
|
|
"""
|
|
intervention.responsible.registration_office = KonovaCode.objects.get(id=1)
|
|
intervention.responsible.conservation_office = KonovaCode.objects.get(id=2)
|
|
intervention.responsible.registration_file_number = "test"
|
|
intervention.responsible.conservation_file_number = "test"
|
|
intervention.responsible.handler = self.handler
|
|
intervention.responsible.save()
|
|
intervention.legal.registration_date = datetime.date.fromisoformat("1970-01-01")
|
|
intervention.legal.binding_date = datetime.date.fromisoformat("1970-01-01")
|
|
intervention.legal.process_type = KonovaCode.objects.get(id=3)
|
|
intervention.legal.save()
|
|
intervention.legal.laws.set([KonovaCode.objects.get(id=(4))])
|
|
intervention.geometry.geom = self.create_dummy_geometry()
|
|
intervention.geometry.save()
|
|
intervention.save()
|
|
return intervention
|
|
|
|
def fill_out_compensation(self, compensation: Compensation) -> Compensation:
|
|
""" Adds all required (dummy) data to a compensation
|
|
|
|
Args:
|
|
compensation (Compensation): The compensation which shall be filled out
|
|
|
|
Returns:
|
|
compensation (Compensation): The modified compensation
|
|
"""
|
|
compensation.after_states.add(self.comp_state)
|
|
compensation.before_states.add(self.comp_state)
|
|
compensation.actions.add(self.comp_action)
|
|
compensation.geometry.geom = self.create_dummy_geometry()
|
|
compensation.deadlines.add(self.finished_deadline)
|
|
compensation.geometry.save()
|
|
return compensation
|
|
|
|
def get_conservation_office_code(self):
|
|
""" Returns a dummy KonovaCode as conservation office code
|
|
|
|
Returns:
|
|
|
|
"""
|
|
codelist = KonovaCodeList.objects.get_or_create(
|
|
id=CODELIST_CONSERVATION_OFFICE_ID
|
|
)[0]
|
|
code = KonovaCode.objects.get(id=2)
|
|
codelist.codes.add(code)
|
|
return code
|
|
|
|
def get_registration_office_code(self):
|
|
""" Returns a dummy KonovaCode as conservation office code
|
|
|
|
Returns:
|
|
|
|
"""
|
|
codelist = KonovaCodeList.objects.get_or_create(
|
|
id=CODELIST_REGISTRATION_OFFICE_ID
|
|
)[0]
|
|
code = KonovaCode.objects.get(id=3)
|
|
codelist.codes.add(code)
|
|
return code
|
|
|
|
def fill_out_ema(self, ema):
|
|
""" Adds all required (dummy) data to an Ema
|
|
|
|
Returns:
|
|
"""
|
|
ema.responsible.conservation_office = self.get_conservation_office_code()
|
|
ema.responsible.conservation_file_number = "test"
|
|
ema.responsible.handler = self.handler
|
|
ema.responsible.save()
|
|
ema.after_states.add(self.comp_state)
|
|
ema.before_states.add(self.comp_state)
|
|
ema.actions.add(self.comp_action)
|
|
ema.geometry.geom = self.create_dummy_geometry()
|
|
ema.deadlines.add(self.finished_deadline)
|
|
ema.geometry.save()
|
|
return ema
|
|
|
|
def fill_out_eco_account(self, eco_account):
|
|
""" Adds all required (dummy) data to an EcoAccount
|
|
|
|
Returns:
|
|
"""
|
|
eco_account.legal.registration_date = "2022-01-01"
|
|
eco_account.legal.save()
|
|
eco_account.responsible.conservation_office = self.get_conservation_office_code()
|
|
eco_account.responsible.conservation_file_number = "test"
|
|
eco_account.responsible.handler = self.handler
|
|
eco_account.responsible.save()
|
|
eco_account.after_states.add(self.comp_state)
|
|
eco_account.before_states.add(self.comp_state)
|
|
eco_account.actions.add(self.comp_action)
|
|
eco_account.geometry.geom = self.create_dummy_geometry()
|
|
eco_account.geometry.save()
|
|
eco_account.deductable_surface = eco_account.get_surface_after_states()
|
|
eco_account.deadlines.add(self.finished_deadline)
|
|
eco_account.save()
|
|
return eco_account
|
|
|
|
def assert_equal_geometries(self, geom1: MultiPolygon, geom2: MultiPolygon):
|
|
""" Assert for geometries to be equal
|
|
|
|
Transforms the geometries to matching srids before checking
|
|
|
|
Args:
|
|
geom1 (MultiPolygon): A geometry
|
|
geom2 (MultiPolygon): A geometry
|
|
|
|
Returns:
|
|
|
|
"""
|
|
# Two empty geometries are basically identical - no further testing
|
|
if geom1.empty and geom2.empty:
|
|
self.assertTrue(True)
|
|
return
|
|
|
|
tolerance = 0.001
|
|
if geom1.srid != geom2.srid:
|
|
# Due to prior possible transformation of any of these geometries, we need to make sure there exists a
|
|
# transformation from one coordinate system into the other, which is valid
|
|
geom1.transform(geom2.srid)
|
|
geom2.transform(geom1.srid)
|
|
self.assertTrue(geom1.equals_exact(geom2, tolerance) or geom2.equals_exact(geom1, tolerance))
|
|
|
|
|
|
class BaseViewTestCase(BaseTestCase):
|
|
""" Wraps basic test functionality, reusable for every specialized ViewTestCase
|
|
|
|
"""
|
|
login_url = None
|
|
|
|
class Meta:
|
|
abstract = True
|
|
|
|
@classmethod
|
|
def setUpTestData(cls) -> None:
|
|
super().setUpTestData()
|
|
|
|
def setUp(self) -> None:
|
|
super().setUp()
|
|
self.login_url = reverse("simple-sso-login")
|
|
|
|
def assert_url_success(self, client: Client, urls: list):
|
|
""" Assert for all given urls a direct 200 response
|
|
|
|
Args:
|
|
client (Client): The performing client
|
|
urls (list): An iterable list of urls to be checked
|
|
|
|
Returns:
|
|
|
|
"""
|
|
for url in urls:
|
|
response = client.get(url)
|
|
self.assertEqual(response.status_code, 200, msg=f"Failed for {url}")
|
|
|
|
def assert_url_success_redirect(self, client: Client, urls: dict):
|
|
""" Assert for all given urls a 302 response to a certain location.
|
|
|
|
Assert the redirect being the expected behaviour.
|
|
|
|
Args:
|
|
client (Client): The performing client
|
|
urls (dict): An iterable dict of (urls, redirect_to_url) pairs to be checked
|
|
|
|
Returns:
|
|
|
|
"""
|
|
for url, redirect_to in urls.items():
|
|
response = client.get(url, follow=True)
|
|
# Expect redirects to the landing page
|
|
self.assertEqual(response.redirect_chain[0], (redirect_to, 302), msg=f"Failed for {url}")
|
|
|
|
def assert_url_fail(self, client: Client, urls: list):
|
|
""" Assert for all given urls a direct 302 response
|
|
|
|
Args:
|
|
client (Client): The performing client
|
|
urls (list): An iterable list of urls to be checked
|
|
|
|
Returns:
|
|
|
|
"""
|
|
for url in urls:
|
|
response = client.get(url)
|
|
self.assertEqual(response.status_code, 302, msg=f"Failed for {url}")
|
|
|
|
|
|
class KonovaViewTestCase(BaseViewTestCase):
|
|
""" Holds tests for all regular views, which are not app specific
|
|
|
|
"""
|
|
def setUp(self) -> None:
|
|
super().setUp()
|
|
|
|
geom = self.create_dummy_geometry()
|
|
self.geom_1 = Geometry.objects.create(
|
|
geom=geom,
|
|
)
|
|
|
|
self.home_url = reverse("home")
|
|
|
|
def test_views_logged_in_no_groups(self):
|
|
""" Check correct status code for all requests
|
|
|
|
Assumption: User logged in but has no groups
|
|
|
|
Returns:
|
|
|
|
"""
|
|
# User logged in
|
|
client = Client()
|
|
client.login(username=self.superuser.username, password=self.superuser_pw)
|
|
self.superuser.groups.set([])
|
|
success_urls = [
|
|
self.home_url
|
|
]
|
|
self.assert_url_success(client, success_urls)
|
|
|
|
def test_views_anonymous_user(self):
|
|
""" Check correct status code for all requests
|
|
|
|
Assumption: User logged in but has no groups
|
|
|
|
Returns:
|
|
|
|
"""
|
|
# User not logged in
|
|
client = Client()
|
|
urls = [
|
|
self.home_url
|
|
]
|
|
self.assert_url_fail(client, urls)
|
|
|
|
def test_htmx_parcel_fetch(self):
|
|
""" Tests that the htmx geometry-parcel fetch returns a proper status code and content
|
|
|
|
Returns:
|
|
|
|
"""
|
|
client_user = Client()
|
|
client_user.login(username=self.superuser.username, password=self.superuser_pw)
|
|
|
|
has_parcels = self.geom_1.parcels.all().exists()
|
|
if not has_parcels:
|
|
self.geom_1.update_parcels()
|
|
|
|
htmx_url = reverse("geometry-parcels", args=(self.geom_1.id,))
|
|
response = client_user.get(htmx_url)
|
|
self.assertEqual(response.status_code, 286, "Unexpected status code for HTMX fetch")
|
|
self.assertGreater(len(response.content), 0)
|
|
|
|
|
|
class AutocompleteTestCase(BaseViewTestCase):
|
|
@classmethod
|
|
def setUpTestData(cls) -> None:
|
|
super().setUpTestData()
|
|
cls.atcmplt_accs = reverse("compensation:acc:autocomplete")
|
|
cls.atcmplt_interventions = reverse("intervention:autocomplete")
|
|
cls.atcmplt_code_comp_action = reverse("codelist:compensation-action-autocomplete")
|
|
cls.atcmplt_code_comp_biotope = reverse("codelist:biotope-autocomplete")
|
|
cls.atcmplt_code_comp_law = reverse("codelist:law-autocomplete")
|
|
cls.atcmplt_code_comp_process = reverse("codelist:process-type-autocomplete")
|
|
cls.atcmplt_code_comp_reg_off = reverse("codelist:registration-office-autocomplete")
|
|
cls.atcmplt_code_comp_cons_off = reverse("codelist:conservation-office-autocomplete")
|
|
cls.atcmplt_code_share_user = reverse("user:share-user-autocomplete")
|
|
|
|
def _test_views_anonymous_user(self):
|
|
# ATTENTION: As of the current state of django-autocomplete-light, there is no way to check on authenticated
|
|
# users in a way like @loing_required or anything else. The documentation considers to check on the user's
|
|
# authentication state during get_queryset() of the call. Therefore this test method here will stay here
|
|
# for future clarification but won't be run due to the prefix '_'
|
|
# User not logged in
|
|
client = Client()
|
|
urls = [
|
|
self.atcmplt_accs,
|
|
self.atcmplt_interventions,
|
|
self.atcmplt_code_comp_action,
|
|
self.atcmplt_code_comp_biotope,
|
|
self.atcmplt_code_comp_law,
|
|
self.atcmplt_code_comp_process,
|
|
self.atcmplt_code_comp_reg_off,
|
|
self.atcmplt_code_comp_cons_off,
|
|
self.atcmplt_code_share_user,
|
|
]
|
|
self.assert_url_fail(client, urls)
|
|
|
|
def test_views_logged_in_no_groups(self):
|
|
# User logged in
|
|
client = Client()
|
|
client.login(username=self.superuser.username, password=self.superuser_pw)
|
|
self.superuser.groups.set([])
|
|
urls = [
|
|
self.atcmplt_accs,
|
|
self.atcmplt_interventions,
|
|
self.atcmplt_code_comp_action,
|
|
self.atcmplt_code_comp_biotope,
|
|
self.atcmplt_code_comp_law,
|
|
self.atcmplt_code_comp_process,
|
|
self.atcmplt_code_comp_reg_off,
|
|
self.atcmplt_code_comp_cons_off,
|
|
]
|
|
self.assert_url_success(client, urls)
|
|
|
|
|
|
class BaseWorkflowTestCase(BaseTestCase):
|
|
"""
|
|
Holds base methods and attributes for workflow testing
|
|
|
|
"""
|
|
|
|
client_user = None
|
|
client_anon = None
|
|
|
|
class Meta:
|
|
abstract = True
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
super().setUpTestData()
|
|
|
|
def assert_object_is_deleted(self, obj):
|
|
""" Provides a quick check whether an object has been removed from the database or not
|
|
|
|
Args:
|
|
obj ():
|
|
|
|
Returns:
|
|
|
|
"""
|
|
# Expect the object to be gone from the db
|
|
try:
|
|
obj.refresh_from_db()
|
|
# Well, we should not reach this next line of code, since the object should be gone, therefore not
|
|
# refreshable -> fail!
|
|
self.fail()
|
|
except ObjectDoesNotExist:
|
|
# If we get in here, the test was fine
|
|
pass |