* adds workflow tests or deductions in InterventionWorkflowTestCase
* fixes bugs detected by testing
This commit is contained in:
mpeltriaux 2021-11-10 15:36:18 +01:00
parent d93ff4015b
commit 34fd78be5e
5 changed files with 198 additions and 18 deletions

View File

@ -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'),
] ]

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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)

View File

@ -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