Skip to content

Commit 2512139

Browse files
refactor(tests): Improve test structure
1 parent 8f9f901 commit 2512139

File tree

8 files changed

+128
-234
lines changed

8 files changed

+128
-234
lines changed

tests/test_additional_coverage.py

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
"""
2-
Additional tests to increase coverage for remaining uncovered lines
3-
Targeting: __init__.py (40-42), admin_base.py (223-224, 246-247, 337, 349-351, 356, 359), models.py (206-215)
4-
"""
1+
"""Tests for edge cases and error handling."""
52

63
import sys
74
from unittest.mock import MagicMock, patch
@@ -18,16 +15,15 @@
1815

1916

2017
class TestVersionParsing(TestCase):
21-
"""Test version parsing edge cases - covers __init__.py lines 40-42"""
18+
"""Test version parsing edge cases."""
2219

2320
def test_version_with_build_metadata(self):
24-
"""Test version parsing with build metadata to cover line 40"""
21+
"""Test version parsing with build metadata."""
2522

26-
# Test the exact code path from __init__.py
27-
# We need to test the actual regex parsing logic
23+
# Test regex parsing logic for version strings
2824
import re
2925

30-
# Test a version string that matches the pattern with build metadata
26+
# Test with build metadata
3127
version_string = "1.2.3-alpha.1+build.123"
3228
pattern = (
3329
r"(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?"
@@ -40,21 +36,21 @@ def test_version_with_build_metadata(self):
4036
version_info = (int(major), int(minor), int(patch))
4137
if prerelease:
4238
version_info += (prerelease,)
43-
if build: # This covers line 40
39+
if build:
4440
version_info += (build,)
4541
else:
46-
version_info = (0, 1, 0) # This covers lines 41-42
42+
version_info = (0, 1, 0)
4743

4844
# Verify build metadata was included
4945
assert len(version_info) == 5
5046
assert version_info[-1] == "build.123"
5147

5248
def test_version_parsing_fallback(self):
53-
"""Test version parsing fallback to cover lines 41-42"""
49+
"""Test version parsing with invalid input."""
5450

5551
import re
5652

57-
# Test with invalid version string that won't match regex
53+
# Invalid version string
5854
version_string = "invalid-version"
5955
pattern = (
6056
r"(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?"
@@ -70,14 +66,14 @@ def test_version_parsing_fallback(self):
7066
if build:
7167
version_info += (build,)
7268
else:
73-
version_info = (0, 1, 0) # This covers lines 41-42
69+
version_info = (0, 1, 0)
7470

7571
# Should fallback to default
7672
assert version_info == (0, 1, 0)
7773

7874

7975
class TestAdminBaseExceptions(TestCase):
80-
"""Test admin base exception handling to increase coverage"""
76+
"""Test admin exception handling."""
8177

8278
def setUp(self):
8379
self.admin = BaseAnonymizationAdmin(MaskingRule, AdminSite())
@@ -87,7 +83,7 @@ def setUp(self):
8783
self.request.META = {}
8884

8985
def test_dry_run_batch_with_database_error(self):
90-
"""Test dry run batch database error - covers lines 223-224"""
86+
"""Test dry run batch operation with database error."""
9187

9288
rule = MaskingRule.objects.create(
9389
table_name="test_table", column_name="test_column", function_expr="anon.fake_email()", enabled=True
@@ -101,13 +97,13 @@ def test_dry_run_batch_with_database_error(self):
10197

10298
result = self.admin._execute_dry_run_batch(queryset, self.admin.apply_rule_operation, "apply")
10399

104-
# Should handle the exception and return it in errors (covers lines 223-224)
100+
# Should handle the exception and return it in errors
105101
assert result["applied_count"] == 0
106102
assert len(result["errors"]) > 0
107103
assert "Database error" in result["errors"][0]
108104

109105
def test_transaction_batch_with_database_error(self):
110-
"""Test transaction batch database error - covers lines 246-247"""
106+
"""Test transaction batch operation with database error."""
111107

112108
rule = MaskingRule.objects.create(
113109
table_name="test_table", column_name="test_column", function_expr="anon.fake_email()", enabled=True
@@ -122,13 +118,13 @@ def test_transaction_batch_with_database_error(self):
122118

123119
result = self.admin._execute_transaction_batch(queryset, self.admin.apply_rule_operation, "apply")
124120

125-
# Should handle the exception and return it in errors (covers lines 246-247)
121+
# Should handle the exception and return it in errors
126122
assert result["applied_count"] == 0
127123
assert len(result["errors"]) > 0
128124
assert "Transaction failed" in result["errors"][0]
129125

130126
def test_enable_rules_no_effect(self):
131-
"""Test enable rules when no rules need enabling - covers line 337"""
127+
"""Test enable operation when all rules are already enabled."""
132128

133129
# Create rules that are already enabled
134130
rule1 = MaskingRule.objects.create(
@@ -150,11 +146,11 @@ def test_enable_rules_no_effect(self):
150146
with patch.object(self.admin, "message_user") as mock_message:
151147
self.admin.enable_rules_operation(self.request, queryset)
152148

153-
# Should show warning message (covers line 337)
149+
# Should show warning message
154150
mock_message.assert_called_with(self.request, "No rules were enabled", level=messages.WARNING)
155151

156152
def test_disable_rules_with_save_failure(self):
157-
"""Test disable rules with save failure - covers lines 349-351"""
153+
"""Test disable operation when save fails."""
158154

159155
rule = MaskingRule.objects.create(
160156
table_name="test_table", column_name="test_column", function_expr="anon.fake_email()", enabled=True
@@ -168,11 +164,11 @@ def test_disable_rules_with_save_failure(self):
168164
with patch.object(self.admin, "message_user"):
169165
self.admin.disable_rules_operation(self.request, queryset)
170166

171-
# Should log the error (covers lines 349-351)
167+
# Should log the error
172168
mock_logger.error.assert_called()
173169

174170
def test_disable_rules_no_enabled_rules(self):
175-
"""Test disable rules when no rules are enabled - covers line 359"""
171+
"""Test disable operation when all rules are already disabled."""
176172

177173
# Create rules that are already disabled
178174
rule = MaskingRule.objects.create(
@@ -187,12 +183,12 @@ def test_disable_rules_no_enabled_rules(self):
187183
with patch.object(self.admin, "message_user") as mock_message:
188184
self.admin.disable_rules_operation(self.request, queryset)
189185

190-
# Should show warning message (covers line 359)
186+
# Should show warning message
191187
mock_message.assert_called_with(self.request, "No rules were disabled", level=messages.WARNING)
192188

193189

194190
class TestSignalDatabaseOperations(TestCase):
195-
"""Test signal database operations - covers models.py lines 206-215"""
191+
"""Test signal database operations."""
196192

197193
def test_signal_database_execution_success(self):
198194
"""Test successful database operation in signal"""
@@ -243,7 +239,7 @@ def test_signal_database_execution_with_exception(self):
243239
rule.enabled = False
244240

245241
# Let the signal execute naturally - it will hit the database
246-
# and handle the error gracefully (covers lines 216-219)
242+
# and handle the error gracefully
247243
from django_postgres_anon.models import handle_rule_disabled
248244

249245
# This should execute the database code and handle any exceptions

tests/test_admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ def test_admin_changelist_view_functions_correctly(admin_setup):
363363
pass
364364

365365

366-
# Additional tests for admin_base.py coverage
366+
# Additional admin tests
367367

368368

369369
@pytest.mark.django_db

tests/test_commands.py

Lines changed: 4 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ def test_anon_drop_interactive_confirmation_accepted(_mock_input):
573573
output = call_command_with_output("anon_drop", "--table", "auth_user")
574574
assert "removal" in output.lower()
575575
# Verify mock was used
576-
assert True # Mock may or may not be called depending on implementation
576+
pass
577577

578578
except CommandError as e:
579579
# May fail due to missing extension
@@ -791,7 +791,7 @@ def test_anon_fix_permissions_command():
791791
output = str(mock_stdout.write.call_args_list)
792792
assert "Failed" in output or "failed" in output.lower()
793793

794-
# Test with database error in permission fix (essential for error handling coverage)
794+
# Test with database error in permission fix
795795
from io import StringIO
796796

797797
from django.db import DatabaseError
@@ -809,53 +809,13 @@ def test_anon_fix_permissions_command():
809809
MaskedRole.objects.all().delete()
810810

811811

812-
@pytest.mark.django_db
813-
def test_create_masked_role_behavior():
814-
"""Test create_masked_role behavioral outcomes"""
815-
from django_postgres_anon.utils import create_masked_role
816-
817-
# Behavioral test: create_masked_role should handle various scenarios gracefully
818-
# and return a boolean indicating success/failure
819-
820-
# Test 1: Creating a role (may succeed or fail depending on DB permissions)
821-
result = create_masked_role("behavioral_test_role")
822-
assert isinstance(result, bool) # Should always return a boolean
823-
824-
# Test 2: Creating a role with inheritance (should handle missing base role gracefully)
825-
result_with_inheritance = create_masked_role("test_role_with_inheritance", inherit_from="nonexistent_base")
826-
assert isinstance(result_with_inheritance, bool) # Should handle gracefully
827-
828-
829-
@pytest.mark.django_db
830-
def test_role_switching_behavior():
831-
"""Test role switching behavioral outcomes"""
832-
from django_postgres_anon.context_managers import database_role
833-
from django_postgres_anon.utils import switch_to_role
834-
835-
# Behavioral test: switch_to_role should return boolean indicating success
836-
result = switch_to_role("test_role", auto_create=False)
837-
assert isinstance(result, bool)
838-
839-
# Behavioral test: switch_to_role with auto_create should handle creation attempts
840-
result_with_create = switch_to_role("test_role_auto", auto_create=True)
841-
assert isinstance(result_with_create, bool)
842-
843-
# Behavioral test: database_role context manager should handle nonexistent roles
844-
try:
845-
with database_role("nonexistent_role"):
846-
pass
847-
except RuntimeError:
848-
# This is expected behavior for nonexistent roles
849-
pass
850-
851-
852812
@pytest.mark.django_db
853813
def test_masked_role_record_management():
854-
"""Test behavioral aspects of masked role record management"""
814+
"""Test masked role record management"""
855815
from django_postgres_anon.context_managers import _update_masked_role_record
856816
from django_postgres_anon.models import MaskedRole
857817

858-
# Behavioral test: updating role record for existing applied role should not create duplicates
818+
# Updating role record for existing applied role should not create duplicates
859819
MaskedRole.objects.create(role_name="existing_role", is_applied=True)
860820
initial_count = MaskedRole.objects.filter(role_name="existing_role").count()
861821

@@ -865,34 +825,5 @@ def test_masked_role_record_management():
865825
final_count = MaskedRole.objects.filter(role_name="existing_role").count()
866826
assert final_count == initial_count
867827

868-
# Behavioral test: updating role record should handle errors gracefully (no exceptions)
869-
try:
870-
_update_masked_role_record("any_role_name")
871-
# Should complete without raising exceptions
872-
except Exception:
873-
pytest.fail("_update_masked_role_record should handle errors gracefully")
874-
875828
# Cleanup
876829
MaskedRole.objects.all().delete()
877-
878-
879-
@pytest.mark.django_db
880-
def test_role_creation_with_inheritance():
881-
"""Test role creation behavioral aspects with inheritance"""
882-
from django_postgres_anon.utils import create_masked_role, switch_to_role
883-
884-
# Behavioral test: Role creation with inheritance should handle missing base roles gracefully
885-
result = create_masked_role("test_inheritance_role", inherit_from="nonexistent_base_role")
886-
assert isinstance(result, bool) # Should return boolean regardless of base role existence
887-
888-
# Behavioral test: Role creation with valid inheritance should work
889-
result_valid = create_masked_role("test_role_2", inherit_from="postgres") # postgres typically exists
890-
assert isinstance(result_valid, bool)
891-
892-
# Behavioral test: Masked roles should attempt to set appropriate search paths
893-
# This tests the "mask" in role name behavior without mocking internals
894-
result_masked = switch_to_role("mask_test_role", auto_create=False)
895-
assert isinstance(result_masked, bool)
896-
897-
result_regular = switch_to_role("regular_test_role", auto_create=False)
898-
assert isinstance(result_regular, bool)

tests/test_core.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -271,9 +271,9 @@ def test_masked_role_string_representation(self):
271271
class TestAnonConfiguration:
272272
"""Test anonymization configuration behavior"""
273273

274-
def test_config_has_essential_properties(self):
275-
"""Configuration provides all essential settings"""
276-
essential_properties = [
274+
@pytest.mark.parametrize(
275+
"prop",
276+
[
277277
"default_masked_role",
278278
"masked_group",
279279
"anonymized_data_role",
@@ -282,15 +282,15 @@ def test_config_has_essential_properties(self):
282282
"validate_functions",
283283
"allow_custom_functions",
284284
"enable_logging",
285-
]
286-
287-
for prop in essential_properties:
288-
assert hasattr(anon_config, prop)
285+
],
286+
)
287+
def test_config_has_essential_properties(self, prop):
288+
"""Configuration provides all essential settings"""
289+
assert hasattr(anon_config, prop)
289290

290-
def test_config_provides_sensible_defaults(self):
291-
"""Configuration has reasonable default values"""
292-
# These should not be None
293-
non_null_defaults = [
291+
@pytest.mark.parametrize(
292+
"prop",
293+
[
294294
"default_masked_role",
295295
"masked_group",
296296
"anonymized_data_role",
@@ -299,11 +299,12 @@ def test_config_provides_sensible_defaults(self):
299299
"validate_functions",
300300
"allow_custom_functions",
301301
"enable_logging",
302-
]
303-
304-
for prop in non_null_defaults:
305-
value = getattr(anon_config, prop)
306-
assert value is not None, f"Config {prop} should have a default value"
302+
],
303+
)
304+
def test_config_provides_sensible_defaults(self, prop):
305+
"""Configuration has reasonable default values"""
306+
value = getattr(anon_config, prop)
307+
assert value is not None, f"Config {prop} should have a default value"
307308

308309
def test_config_types_are_correct(self):
309310
"""Configuration values have expected types"""

0 commit comments

Comments
 (0)