#19 Tests
* adds workflow tests or deductions in InterventionWorkflowTestCase * fixes bugs detected by testing
This commit is contained in:
parent
08d023092f
commit
bcee58700a
@ -32,7 +32,7 @@ urlpatterns = [
|
|||||||
path('document/<doc_id>/remove/', remove_document_view, name='acc-remove-doc'),
|
path('document/<doc_id>/remove/', remove_document_view, name='acc-remove-doc'),
|
||||||
|
|
||||||
# Eco-account deductions
|
# Eco-account deductions
|
||||||
path('<id>/remove/<deduction_id>', deduction_remove_view, name='deduction-remove'),
|
path('<id>/remove/<deduction_id>', deduction_remove_view, name='acc-remove-deduction'),
|
||||||
path('<id>/deduct/new', new_deduction_view, name='acc-new-deduction'),
|
path('<id>/deduct/new', new_deduction_view, name='acc-new-deduction'),
|
||||||
|
|
||||||
]
|
]
|
@ -60,7 +60,7 @@
|
|||||||
<td class="align-middle">{{ deduction.created.timestamp|default_if_none:""|naturalday}}</td>
|
<td class="align-middle">{{ deduction.created.timestamp|default_if_none:""|naturalday}}</td>
|
||||||
<td>
|
<td>
|
||||||
{% if is_default_member and has_access %}
|
{% if is_default_member and has_access %}
|
||||||
<button data-form-url="{% url 'compensation:deduction-remove' deduction.account.id deduction.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove Deduction' %}">
|
<button data-form-url="{% url 'compensation:acc-remove-deduction' deduction.account.id deduction.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove Deduction' %}">
|
||||||
{% fa5_icon 'trash' %}
|
{% fa5_icon 'trash' %}
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
<td class="align-middle">{{ deduction.created.timestamp|default_if_none:""|naturalday}}</td>
|
<td class="align-middle">{{ deduction.created.timestamp|default_if_none:""|naturalday}}</td>
|
||||||
<td>
|
<td>
|
||||||
{% if is_default_member and has_access %}
|
{% if is_default_member and has_access %}
|
||||||
<button data-form-url="{% url 'compensation:deduction-remove' deduction.account.id deduction.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove Deduction' %}">
|
<button data-form-url="{% url 'compensation:acc-remove-deduction' deduction.account.id deduction.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove Deduction' %}">
|
||||||
{% fa5_icon 'trash' %}
|
{% fa5_icon 'trash' %}
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -11,10 +11,11 @@ from django.contrib.auth.models import Group
|
|||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from compensation.models import Payment
|
from compensation.models import Payment, EcoAccountDeduction
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from konova.settings import DEFAULT_GROUP
|
from konova.settings import DEFAULT_GROUP
|
||||||
from konova.tests.test_views import BaseWorkflowTestCase
|
from konova.tests.test_views import BaseWorkflowTestCase
|
||||||
|
from user.models import UserActionLogEntry, UserAction
|
||||||
|
|
||||||
|
|
||||||
class InterventionWorkflowTestCase(BaseWorkflowTestCase):
|
class InterventionWorkflowTestCase(BaseWorkflowTestCase):
|
||||||
@ -31,7 +32,7 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase):
|
|||||||
default_group = Group.objects.get(name=DEFAULT_GROUP)
|
default_group = Group.objects.get(name=DEFAULT_GROUP)
|
||||||
cls.superuser.groups.set([default_group])
|
cls.superuser.groups.set([default_group])
|
||||||
|
|
||||||
def test_new_normal_case(self):
|
def test_new(self):
|
||||||
"""
|
"""
|
||||||
Checks a 'normal' case of creating a new intervention.
|
Checks a 'normal' case of creating a new intervention.
|
||||||
We expect the user to be redirected as expected right away to the detail page of the new intervention.
|
We expect the user to be redirected as expected right away to the detail page of the new intervention.
|
||||||
@ -93,9 +94,6 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase):
|
|||||||
## BUT: Payments are added on the intervention detail page. Therefore it's part of a regular intervention workflow.
|
## BUT: Payments are added on the intervention detail page. Therefore it's part of a regular intervention workflow.
|
||||||
new_payment_url = reverse("compensation:pay-new", args=(self.intervention.id,))
|
new_payment_url = reverse("compensation:pay-new", args=(self.intervention.id,))
|
||||||
|
|
||||||
# Create default detail page of intervention
|
|
||||||
detail_url = reverse("intervention:detail", args=(self.intervention.id,))
|
|
||||||
|
|
||||||
# Make sure there are no payments on the intervention, yet
|
# Make sure there are no payments on the intervention, yet
|
||||||
self.assertEqual(0, self.intervention.payments.count())
|
self.assertEqual(0, self.intervention.payments.count())
|
||||||
|
|
||||||
@ -145,22 +143,16 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Expect the payment to be gone from the db and therefore from the intervention as well
|
# Expect the payment to be gone from the db and therefore from the intervention as well
|
||||||
try:
|
self.assert_object_is_deleted(payment)
|
||||||
payment.refresh_from_db()
|
|
||||||
# Well, we should not reach this next line of code, since the payment should be gone, therefore not
|
|
||||||
# refreshable -> fail!
|
|
||||||
self.fail()
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
# If we get in here, the test was fine
|
|
||||||
pass
|
|
||||||
# Now make sure the intervention has no payments anymore
|
# Now make sure the intervention has no payments anymore
|
||||||
self.assertEqual(0, self.intervention.payments.count())
|
self.assertEqual(0, self.intervention.payments.count())
|
||||||
|
|
||||||
def test_changing_payment_test_case(self):
|
def test_payments(self):
|
||||||
"""
|
"""
|
||||||
Checks a 'normal' case of adding a payment.
|
Checks a 'normal' case of adding a payment.
|
||||||
We expect a new payment to be addable to an existing intervention
|
We expect a new payment to be addable to an existing intervention
|
||||||
We expect a payment to be deletable to an existing intervention
|
We expect a payment to be deletable from an existing intervention
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
@ -170,3 +162,171 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase):
|
|||||||
|
|
||||||
# Now remove the payment again
|
# Now remove the payment again
|
||||||
self.subtest_delete_payment(payment)
|
self.subtest_delete_payment(payment)
|
||||||
|
|
||||||
|
def subtest_add_deduction_fail_positive(self, new_url: str, post_data: dict, test_surface: float):
|
||||||
|
""" Holds tests for postivie fails of new deduction creation
|
||||||
|
|
||||||
|
Reasons for failing are:
|
||||||
|
* EcoAccount does not provide enough 'deductable_surface'
|
||||||
|
* EcoAccount is not recorded (not "approved"), yet
|
||||||
|
* EcoAccount is not shared with performing user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
new_url (str): The url to send the post data to
|
||||||
|
post_data (dict): The form post data to be sent
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Before running fail positive tests, we need to have an account in a (normally) fine working state
|
||||||
|
self.assertIsNotNone(self.eco_account.recorded) # -> is recorded
|
||||||
|
self.assertGreater(self.eco_account.deductable_surface, test_surface) # -> has more deductable surface than we need
|
||||||
|
self.assertIn(self.superuser, self.eco_account.users.all()) # -> is shared with the performing user
|
||||||
|
|
||||||
|
# Count the number of already existing deductions in total and for the account for later comparison
|
||||||
|
num_deductions = self.eco_account.deductions.count()
|
||||||
|
num_deductions_total = EcoAccountDeduction.objects.count()
|
||||||
|
|
||||||
|
# First test that a deduction can not be created, if the account does not provide
|
||||||
|
# enough surface for the deduction. So we modify the deductable surface of the account
|
||||||
|
self.eco_account.deductable_surface = 0
|
||||||
|
self.eco_account.save()
|
||||||
|
|
||||||
|
# Now perform the (expected) failing request
|
||||||
|
self.client_user.post(new_url, post_data)
|
||||||
|
|
||||||
|
# Expect no changes at all, since the deduction should not have been created
|
||||||
|
self.assertEqual(num_deductions, self.eco_account.deductions.count())
|
||||||
|
self.assertEqual(num_deductions_total, EcoAccountDeduction.objects.count())
|
||||||
|
|
||||||
|
# Now restore the deductable surface to a valid size back again but remove the user from the shared list
|
||||||
|
self.eco_account.deductable_surface = test_surface + 100.00
|
||||||
|
self.eco_account.users.set([])
|
||||||
|
self.eco_account.save()
|
||||||
|
|
||||||
|
# Now perform the (expected) failing request (again)
|
||||||
|
self.client_user.post(new_url, post_data)
|
||||||
|
|
||||||
|
# Expect no changes at all, since the account is not shared
|
||||||
|
self.assertEqual(num_deductions, self.eco_account.deductions.count())
|
||||||
|
self.assertEqual(num_deductions_total, EcoAccountDeduction.objects.count())
|
||||||
|
|
||||||
|
# Restore the sharing but remove the recording state
|
||||||
|
self.eco_account.users.set([self.superuser])
|
||||||
|
self.eco_account.recorded.delete()
|
||||||
|
self.eco_account.refresh_from_db()
|
||||||
|
self.eco_account.save()
|
||||||
|
|
||||||
|
# Now perform the (expected) failing request (again)
|
||||||
|
self.client_user.post(new_url, post_data)
|
||||||
|
|
||||||
|
# Expect no changes at all, since the account is no shared with the user, yet
|
||||||
|
self.assertEqual(num_deductions, self.eco_account.deductions.count())
|
||||||
|
self.assertEqual(num_deductions_total, EcoAccountDeduction.objects.count())
|
||||||
|
|
||||||
|
def subtest_add_deduction_normal(self, new_url: str, post_data: dict, test_surface: float):
|
||||||
|
""" Holds tests on working ("normal") deduction creation
|
||||||
|
|
||||||
|
Args:
|
||||||
|
new_url (str): The url to send the post data to
|
||||||
|
post_data (dict): The form post data to be sent
|
||||||
|
test_surface (float): The expected surface of the deduction
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Prepare the account for a working situation (enough deductable surface, recorded and shared)
|
||||||
|
self.eco_account.deductable_surface = 10000.00
|
||||||
|
if self.eco_account.recorded is None:
|
||||||
|
rec_action = UserActionLogEntry.objects.create(
|
||||||
|
user=self.superuser,
|
||||||
|
action=UserAction.RECORDED
|
||||||
|
)
|
||||||
|
self.eco_account.recorded = rec_action
|
||||||
|
self.eco_account.users.set([self.superuser])
|
||||||
|
self.eco_account.save()
|
||||||
|
|
||||||
|
# Run the request
|
||||||
|
self.client_user.post(new_url, post_data)
|
||||||
|
|
||||||
|
# Expect the deduction to be created, since all constraints are fulfilled
|
||||||
|
self.assertEqual(1, self.eco_account.deductions.count())
|
||||||
|
self.assertEqual(1, EcoAccountDeduction.objects.count())
|
||||||
|
|
||||||
|
# Make sure the deduction contains the expected data
|
||||||
|
deduction = EcoAccountDeduction.objects.first()
|
||||||
|
self.assertEqual(deduction.surface, test_surface)
|
||||||
|
self.assertEqual(deduction.intervention, self.intervention)
|
||||||
|
self.assertEqual(deduction.account, self.eco_account)
|
||||||
|
|
||||||
|
# Return deduction for further usage in tests
|
||||||
|
return deduction
|
||||||
|
|
||||||
|
def subtest_add_deduction(self):
|
||||||
|
""" Holds test for adding a new deduction
|
||||||
|
|
||||||
|
Contains tests for
|
||||||
|
* positive fails (as expected)
|
||||||
|
* normal cases
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Create the url for creating a new deduction
|
||||||
|
new_url = reverse("compensation:acc-new-deduction", args=(self.eco_account.id,))
|
||||||
|
|
||||||
|
# Prepare the form data
|
||||||
|
test_surface = 100.00
|
||||||
|
post_data = {
|
||||||
|
"surface": test_surface,
|
||||||
|
"account": self.eco_account.id,
|
||||||
|
"intervention": self.intervention.id,
|
||||||
|
}
|
||||||
|
# Run some tests for regular, working cases
|
||||||
|
deduction = self.subtest_add_deduction_normal(new_url, post_data, test_surface)
|
||||||
|
|
||||||
|
# Run some tests where we expect the creation of a deduction to fail (as expected)
|
||||||
|
self.subtest_add_deduction_fail_positive(new_url, post_data, test_surface)
|
||||||
|
|
||||||
|
# Return deduction for further usage in tests
|
||||||
|
return deduction
|
||||||
|
|
||||||
|
def subtest_delete_deduction(self, deduction: EcoAccountDeduction):
|
||||||
|
""" Holds test for deleting a deduction
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Prepare url for deleting of this deduction
|
||||||
|
delete_url = reverse("compensation:acc-remove-deduction", args=(self.eco_account.id, deduction.id,))
|
||||||
|
post_data = {
|
||||||
|
"confirm": True
|
||||||
|
}
|
||||||
|
# Save number of current deductions for later comparison
|
||||||
|
num_deductions = self.eco_account.deductions.count()
|
||||||
|
num_deductions_total = EcoAccountDeduction.objects.count()
|
||||||
|
|
||||||
|
# Run request
|
||||||
|
self.client_user.post(delete_url, post_data)
|
||||||
|
|
||||||
|
# Expect the deduction to be gone from the db and relations
|
||||||
|
self.assertEqual(num_deductions - 1, self.eco_account.deductions.count())
|
||||||
|
self.assertEqual(num_deductions_total - 1, EcoAccountDeduction.objects.count())
|
||||||
|
|
||||||
|
# Expect the deduction to be totally gone
|
||||||
|
self.assert_object_is_deleted(deduction)
|
||||||
|
|
||||||
|
def test_deduction(self):
|
||||||
|
"""
|
||||||
|
Checks a 'normal case of adding a deduction.
|
||||||
|
We expect a new deduction to be addable to an existing intervention
|
||||||
|
We expect a deduction to be deletable
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Create a new deduction for the default intervention
|
||||||
|
deduction = self.subtest_add_deduction()
|
||||||
|
|
||||||
|
# Now remove the deduction again
|
||||||
|
self.subtest_delete_deduction(deduction)
|
||||||
|
@ -8,6 +8,7 @@ Created on: 26.10.21
|
|||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
|
|
||||||
from django.contrib.auth.models import User, Group
|
from django.contrib.auth.models import User, Group
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.test import TestCase, Client
|
from django.test import TestCase, Client
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
@ -355,3 +356,22 @@ class BaseWorkflowTestCase(BaseTestCase):
|
|||||||
cls.client_user = Client()
|
cls.client_user = Client()
|
||||||
cls.client_user.login(username=cls.superuser.username, password=cls.superuser_pw)
|
cls.client_user.login(username=cls.superuser.username, password=cls.superuser_pw)
|
||||||
cls.client_anon = Client()
|
cls.client_anon = Client()
|
||||||
|
|
||||||
|
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
|
Loading…
Reference in New Issue
Block a user