Testing¶
Overview¶
# Run all tests
pytest tests/ -v
# With coverage
pytest tests/ --cov=bank_parser --cov-report=term-missing
# Specific test file
pytest tests/test_banks.py -v
# Specific test
pytest tests/test_models.py::test_transaction_creation -v
Test Structure¶
tests/
├── test_models.py # Pydantic model validation
├── test_banks.py # Parser instantiation
└── fixtures/ # Sample PDFs (gitignored)
├── hdfc/
├── icici/
├── sbi/
└── axis/
Test Categories¶
1. Model Tests (test_models.py)¶
Tests for Pydantic models:
def test_transaction_creation():
txn = Transaction(
date=date(2024, 1, 15),
description="UPI-PAYMENT",
debit=Decimal("500.00"),
credit=None,
balance=Decimal("45000.00"),
ref_no="UPI123",
category="debit",
)
assert txn.category == "debit"
def test_transaction_to_dict():
txn = Transaction(...)
d = txn.to_dict()
assert d["date"] == "2024-01-15"
assert d["debit"] == 500.0
2. Bank Parser Tests (test_banks.py)¶
Tests for parser instantiation:
def test_hdfc_parser_instantiation():
parser = HDFCParser("dummy.pdf")
assert parser.bank_code == "hdfc"
assert parser.bank_name == "HDFC Bank"
3. Integration Tests (Future)¶
def test_hdfc_parsing():
# Requires sample PDF in fixtures
parser = HDFCParser("tests/fixtures/hdfc/savings.pdf")
statement = parser.parse()
assert len(statement.transactions) > 0
assert all(isinstance(t, Transaction) for t in statement.transactions)
Running Tests¶
Local Development¶
# Install dev dependencies
pip install -e ".[dev]"
# Run all
pytest tests/ -v
# With coverage
pytest tests/ --cov=bank_parser --cov-report=html
# Watch mode
ptw tests/ -- -v
CI Pipeline¶
# .github/workflows/ci.yml
- name: Run tests
run: |
pytest tests/ -v --cov=bank_parser --cov-report=xml
Adding Tests for New Bank¶
- Add sample PDFs to
tests/fixtures/yourbank/(anonymized) - Create
tests/test_yourbank.py:
from bank_parser.banks.yourbank import YourBankParser
def test_yourbank_parser_instantiation():
parser = YourBankParser("dummy.pdf")
assert parser.bank_code == "yourbank"
assert parser.bank_name == "Your Bank Name"
def test_yourbank_savings_parsing():
# Requires fixture
parser = YourBankParser("tests/fixtures/yourbank/savings.pdf")
statement = parser.parse()
assert statement.bank == "yourbank"
assert len(statement.transactions) > 0
- Add anonymized PDF fixtures (or skip if unavailable)
Test Utilities¶
Base Parser Helpers¶
from bank_parser.banks.base import BaseBankParser
# Test date parsing
parser = HDFCParser("")
assert parser.parse_date("15/01/2024").date() == date(2024, 1, 15)
# Test amount parsing
assert parser.parse_amount("1,000.00") == Decimal("1000.00")
assert parser.parse_amount("") is None
Fixture Management¶
import pytest
from pathlib import Path
FIXTURES_DIR = Path(__file__).parent / "fixtures"
def get_fixture_path(bank: str, name: str) -> Path:
return FIXTURES_DIR / bank / f"{name}.pdf"
Mocking PDF Extraction¶
from unittest.mock import patch, MagicMock
@patch("pdfplumber.open")
def test_parse_with_mock(mock_open):
mock_pdf = MagicMock()
mock_page = MagicMock()
mock_page.extract_text.return_value = "15/01/2024 UPI Payment 500.00 45000.00"
mock_pdf.pages = [mock_page]
mock_open.return_value.__enter__.return_value = mock_pdf
parser = HDFCParser("dummy.pdf")
statement = parser.parse()
assert len(statement.transactions) == 1
Coverage Goals¶
| Component | Target |
|---|---|
| Models | 100% |
| Core API | 90%+ |
| Bank Parsers | 80%+ |
| CLI | 70%+ |
Pre-commit Hooks¶
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.0
hooks:
- id: ruff
- repo: https://github.com/psf/black
rev: 24.0.0
hooks:
- id: black
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.0.0
hooks:
- id: mypy
Run: pre-commit run --all-files