From e95043467108a410a198fddc8db0d5000f4b7f12 Mon Sep 17 00:00:00 2001 From: Neda Moeini <neda.moeini@geant.org> Date: Fri, 28 Feb 2025 11:06:54 +0100 Subject: [PATCH] Improve the tests by using a helper function for modifying the input file and removed the redundant code --- pyproject.toml | 2 +- test/conftest.py | 4 +- test/test_file_validator/test_forms.py | 89 +++++++++++++------------- 3 files changed, 47 insertions(+), 48 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 981838d..4650bd8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,7 @@ line-length = 120 ban-relative-imports = "all" [tool.ruff.lint.per-file-ignores] -"test/*" = ["S101", "ARG001",] +"test/*" = ["ARG001", "D", "S101", "PLR2004", "PLR0917", "PLR0914", "PLC0415", "PLC2701"] [tool.pytest.ini_options] DJANGO_SETTINGS_MODULE = "test.settings" diff --git a/test/conftest.py b/test/conftest.py index 74bbc11..f91236c 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -9,7 +9,7 @@ from sage_validation.file_validator.models import MeoCostCentres, MeoValidSuppli @pytest.fixture -def sample_input_file(): +def sample_input_file() -> SimpleUploadedFile: """Create a sample valid CSV file for testing.""" csv_headers_list = [ "AccountNumber", @@ -96,7 +96,7 @@ def sample_input_file(): return SimpleUploadedFile("test.csv", f"{csv_headers}\n{csv_content}".encode(), content_type="text/csv") @pytest.fixture -def mock_meo_database(mocker): +def mock_meo_database(mocker: MagicMock)-> None: """Mock the meo database since it's read-only.""" fake = Faker() diff --git a/test/test_file_validator/test_forms.py b/test/test_file_validator/test_forms.py index b169538..b5df108 100644 --- a/test/test_file_validator/test_forms.py +++ b/test/test_file_validator/test_forms.py @@ -1,19 +1,46 @@ """Tests for the file_validator forms.""" import csv import io +from unittest.mock import MagicMock from django.core.files.uploadedfile import SimpleUploadedFile from sage_validation.file_validator.forms import CSVUploadForm -def test_valid_csv_upload(sample_input_file, mock_meo_database): +def create_modified_csv(sample_file: SimpleUploadedFile, modifications: dict[str, str]) -> SimpleUploadedFile: + """ + Modify specific fields in the first row of a CSV file and return a new SimpleUploadedFile. + + Args: + sample_file (SimpleUploadedFile): The original CSV file. + modifications (dict): Dictionary of column names to modified values. + + Returns: + SimpleUploadedFile: The modified CSV file. + """ + csv_content = sample_file.read().decode("utf-8").splitlines() + reader = csv.DictReader(csv_content) + rows = list(reader) + + for key, value in modifications.items(): + rows[0][key] = value + + output = io.StringIO() + writer = csv.DictWriter(output, fieldnames=reader.fieldnames or []) + writer.writeheader() + writer.writerows(rows) + + return SimpleUploadedFile("test_modified.csv", output.getvalue().encode("utf-8"), content_type="text/csv") + + +def test_valid_csv_upload(sample_input_file: SimpleUploadedFile, mock_meo_database: MagicMock) -> None: """Test CSV upload with valid data.""" form = CSVUploadForm(files={"file": sample_input_file}) assert form.is_valid(), f"Form errors: {form.errors}" -def test_invalid_file_extension(): +def test_invalid_file_extension() -> None: """Test form rejects non-CSV files.""" bad_file = SimpleUploadedFile("test.txt", b"Some text content", content_type="text/plain") form = CSVUploadForm(files={"file": bad_file}) @@ -21,7 +48,7 @@ def test_invalid_file_extension(): assert "File must be in CSV format." in form.errors["file"] -def test_missing_required_columns(): +def test_missing_required_columns() -> None: """Test form rejects CSV missing required headers.""" invalid_csv = SimpleUploadedFile("test.csv", b"AccountNumber,CBAccountNumber\n12345,54321", content_type="text/csv") form = CSVUploadForm(files={"file": invalid_csv}) @@ -29,43 +56,19 @@ def test_missing_required_columns(): assert "Missing required columns" in str(form.errors) -def test_source_and_trader_type_validation(sample_input_file, mock_meo_database): +def test_source_and_trader_type_validation(sample_input_file: SimpleUploadedFile, mock_meo_database: MagicMock) -> None: """Test validation for Source and SYSTraderTranType columns.""" - csv_content = sample_input_file.read().decode("utf-8").splitlines() - reader = csv.DictReader(csv_content) - rows = list(reader) - - # Modify the first row's "Source" and "SYSTraderTranType" values - rows[0]["Source"] = "90" # Change Source from 80 to 90 - rows[0]["SYSTraderTranType"] = "5" # Change SYSTraderTranType from 4 to 5 - - # Rebuild the CSV with modified values - output = io.StringIO() - writer = csv.DictWriter(output, fieldnames=reader.fieldnames) - writer.writeheader() - writer.writerows(rows) - modified_file = SimpleUploadedFile("test_modified.csv", output.getvalue().encode("utf-8"), content_type="text/csv") - + modified_file = create_modified_csv(sample_input_file, {"Source": "90", "SYSTraderTranType": "5"}) form = CSVUploadForm(files={"file": modified_file}) assert not form.is_valid() assert "Row 1: 'Source' must be 80" in form.errors["file"][0] assert "Row 1: 'SYSTraderTranType' must be 4" in form.errors["file"][1] -def test_validate_nominal_analysis_account(sample_input_file, mock_meo_database): +def test_validate_nominal_analysis_account(sample_input_file: SimpleUploadedFile, mock_meo_database: MagicMock) -> None: """Test validation for nominal analysis account.""" - csv_content = sample_input_file.read().decode("utf-8").splitlines() - reader = csv.DictReader(csv_content) - rows = list(reader) - rows[0]["NominalAnalysisNominalAnalysisNarrative/1"] = "Invalid Name" - - # Rebuild the CSV with modified values - output = io.StringIO() - writer = csv.DictWriter(output, fieldnames=reader.fieldnames) - writer.writeheader() - writer.writerows(rows) - modified_file = SimpleUploadedFile("test_modified.csv", output.getvalue().encode("utf-8"), content_type="text/csv") - + modified_file = create_modified_csv(sample_input_file, + {"NominalAnalysisNominalAnalysisNarrative/1": "Invalid Name"}) form = CSVUploadForm(files={"file": modified_file}) assert not form.is_valid() assert form.errors["file"][0] == ( @@ -73,20 +76,16 @@ def test_validate_nominal_analysis_account(sample_input_file, mock_meo_database) ", but found 'Invalid Name'.") -def test_validate_nc_cc_dep_combination_against_meo_sage_account(sample_input_file, mock_meo_database): +def test_validate_nc_cc_dep_combination_against_meo_sage_account( + sample_input_file: SimpleUploadedFile, mock_meo_database: MagicMock +) -> None: """Test validation for nominal analysis fields against MEO valid Sage accounts.""" - csv_content = sample_input_file.read().decode("utf-8").splitlines() - reader = csv.DictReader(csv_content) - rows = list(reader) - - rows[0]["NominalAnalysisNominalCostCentre/1"] = "Invalid_CC" - rows[0]["NominalAnalysisNominalAccountNumber/1"] = "Invalid_Account" - - output = io.StringIO() - writer = csv.DictWriter(output, fieldnames=reader.fieldnames) - writer.writeheader() - writer.writerows(rows) - modified_file = SimpleUploadedFile("test_modified.csv", output.getvalue().encode("utf-8"), content_type="text/csv") + modified_file = create_modified_csv( + sample_input_file, + { + "NominalAnalysisNominalCostCentre/1": "Invalid_CC", + "NominalAnalysisNominalAccountNumber/1": "Invalid_Account" + }) form = CSVUploadForm(files={"file": modified_file}) assert not form.is_valid() -- GitLab