Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# Virtual environments
venv/
env/
ENV/
env.bak/
venv.bak/
.venv/

# Testing
.pytest_cache/
.coverage
htmlcov/
coverage.xml
*.cover
*.py,cover
.hypothesis/
.tox/

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Claude Code
.claude/*

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# mypy
.mypy_cache/
.dmypy.json
dmypy.json
282 changes: 282 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

80 changes: 80 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
[tool.poetry]
name = "python-api-demo"
version = "0.1.0"
description = "Python API demonstration project"
authors = ["Your Name <you@example.com>"]
readme = "README.md"
packages = [{include = "code"}]

[tool.poetry.dependencies]
python = "^3.8"

[tool.poetry.group.dev.dependencies]
pytest = "^7.4.0"
pytest-cov = "^4.1.0"
pytest-mock = "^3.11.1"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--strict-markers",
"--strict-config",
"--verbose",
"--cov=code",
"--cov-report=term-missing",
"--cov-report=html:htmlcov",
"--cov-report=xml:coverage.xml",
"--cov-fail-under=80",
]
markers = [
"unit: Unit tests",
"integration: Integration tests",
"slow: Slow running tests",
]

[tool.coverage.run]
source = ["code"]
omit = [
"tests/*",
"*/venv/*",
"*/.venv/*",
"*/env/*",
"*/.env/*",
"*/site-packages/*",
"*/__pycache__/*",
"*/migrations/*",
"*/alembic/*",
"setup.py",
"conftest.py",
]

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]
show_missing = true
skip_covered = false
fail_under = 80

[tool.coverage.html]
directory = "htmlcov"

[tool.coverage.xml]
output = "coverage.xml"
Empty file added tests/__init__.py
Empty file.
127 changes: 127 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import os
import tempfile
import shutil
from pathlib import Path
from typing import Dict, Any

import pytest


@pytest.fixture
def temp_dir():
"""Create a temporary directory for tests."""
temp_path = tempfile.mkdtemp()
yield Path(temp_path)
shutil.rmtree(temp_path)


@pytest.fixture
def temp_file(temp_dir):
"""Create a temporary file for tests."""
temp_file_path = temp_dir / "test_file.txt"
temp_file_path.write_text("test content")
return temp_file_path


@pytest.fixture
def mock_env_vars(monkeypatch):
"""Fixture to provide mock environment variables."""
test_env = {
"TEST_API_KEY": "test_key_123",
"TEST_API_URL": "https://test.api.com",
"TEST_DEBUG": "true"
}

for key, value in test_env.items():
monkeypatch.setenv(key, value)

return test_env


@pytest.fixture
def sample_config():
"""Provide sample configuration for tests."""
return {
"api_key": "test_key",
"base_url": "https://api.example.com",
"timeout": 30,
"retry_count": 3,
"debug": False
}


@pytest.fixture
def mock_api_response():
"""Mock API response data."""
return {
"status": "success",
"code": 200,
"data": {
"id": "123",
"name": "test_item",
"created_at": "2023-01-01T00:00:00Z"
},
"message": "Operation completed successfully"
}


@pytest.fixture
def mock_error_response():
"""Mock API error response data."""
return {
"status": "error",
"code": 400,
"data": None,
"message": "Invalid request parameters"
}


@pytest.fixture(scope="session")
def test_data_dir():
"""Path to test data directory."""
return Path(__file__).parent / "data"


@pytest.fixture
def sample_json_data():
"""Sample JSON data for testing."""
return {
"users": [
{"id": 1, "name": "Alice", "email": "alice@example.com"},
{"id": 2, "name": "Bob", "email": "bob@example.com"}
],
"metadata": {
"total": 2,
"page": 1,
"per_page": 10
}
}


@pytest.fixture
def mock_file_content():
"""Mock file content for testing file operations."""
return "Line 1\nLine 2\nLine 3\n"


@pytest.fixture(autouse=True)
def clean_environment():
"""Clean up environment after each test."""
yield
# Cleanup code can be added here if needed


@pytest.fixture
def mock_datetime(mocker):
"""Mock datetime for consistent testing."""
mock_dt = mocker.patch('datetime.datetime')
mock_dt.now.return_value = mocker.MagicMock()
mock_dt.now.return_value.isoformat.return_value = "2023-01-01T12:00:00"
return mock_dt


@pytest.fixture
def captured_logs(caplog):
"""Capture and return logs for testing."""
yield caplog
caplog.clear()
Empty file added tests/integration/__init__.py
Empty file.
95 changes: 95 additions & 0 deletions tests/test_infrastructure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""
Infrastructure validation tests to ensure the testing setup is working correctly.
"""
import os
import sys
from pathlib import Path

import pytest


class TestInfrastructure:
"""Test the testing infrastructure setup."""

def test_pytest_is_working(self):
"""Basic test to verify pytest is functioning."""
assert True

def test_python_version(self):
"""Verify Python version compatibility."""
assert sys.version_info >= (3, 8), "Python 3.8+ is required"

def test_project_structure(self):
"""Verify the project structure is correct."""
project_root = Path(__file__).parent.parent

# Check main directories exist
assert (project_root / "code").exists(), "code directory should exist"
assert (project_root / "tests").exists(), "tests directory should exist"
assert (project_root / "tests" / "unit").exists(), "tests/unit directory should exist"
assert (project_root / "tests" / "integration").exists(), "tests/integration directory should exist"

# Check configuration files
assert (project_root / "pyproject.toml").exists(), "pyproject.toml should exist"
assert (project_root / ".gitignore").exists(), ".gitignore should exist"

def test_fixtures_available(self, temp_dir, sample_config, mock_api_response):
"""Test that shared fixtures are available and working."""
# Test temp_dir fixture
assert temp_dir.exists()
assert temp_dir.is_dir()

# Test sample_config fixture
assert isinstance(sample_config, dict)
assert "api_key" in sample_config

# Test mock_api_response fixture
assert isinstance(mock_api_response, dict)
assert mock_api_response["status"] == "success"

def test_environment_isolation(self, mock_env_vars):
"""Test that environment variables can be mocked."""
assert os.getenv("TEST_API_KEY") == "test_key_123"
assert os.getenv("TEST_API_URL") == "https://test.api.com"

@pytest.mark.unit
def test_unit_marker(self):
"""Test that custom markers are working."""
assert True

@pytest.mark.integration
def test_integration_marker(self):
"""Test that integration marker is working."""
assert True

def test_mock_functionality(self, mocker):
"""Test that pytest-mock is working correctly."""
# Mock a simple function call
mock_func = mocker.Mock(return_value="mocked_result")
result = mock_func("test_arg")

assert result == "mocked_result"
mock_func.assert_called_once_with("test_arg")

def test_temp_file_fixture(self, temp_file):
"""Test that temporary file fixture works."""
assert temp_file.exists()
assert temp_file.read_text() == "test content"

def test_code_directory_accessible(self):
"""Test that the code directory is accessible for imports."""
project_root = Path(__file__).parent.parent
code_dir = project_root / "code"

assert code_dir.exists()
# Check if we can list Python files in the code directory
python_files = list(code_dir.glob("*.py"))
assert len(python_files) > 0, "Should have Python files in code directory"


@pytest.mark.slow
def test_slow_operation():
"""Example of a slow test that can be skipped with markers."""
import time
time.sleep(0.1) # Simulate slow operation
assert True
Empty file added tests/unit/__init__.py
Empty file.