Mini Project: Automation Script with Tests
Build a data processing automation script with complete test coverage. Combines testing, debugging, clean code, and optimization.
25 min•By Priygop Team•Updated 2026
Tested Automation Script
Tested Automation Script
import unittest
from typing import List, Dict, Optional
# === Data Processor Module ===
class DataProcessor:
"""Process and analyze data records."""
def __init__(self, data: List[Dict]):
self.data = data
self._processed = False
def filter_by(self, key: str, value) -> List[Dict]:
"""Filter records where key matches value."""
return [r for r in self.data if r.get(key) == value]
def sort_by(self, key: str, reverse: bool = False) -> List[Dict]:
"""Sort records by a key."""
return sorted(self.data, key=lambda r: r.get(key, ""), reverse=reverse)
def aggregate(self, key: str) -> Dict[str, int]:
"""Count occurrences of each value for a key."""
counts: Dict[str, int] = {}
for record in self.data:
val = str(record.get(key, "unknown"))
counts[val] = counts.get(val, 0) + 1
return counts
def average(self, key: str) -> Optional[float]:
"""Calculate average of numeric field."""
values = [r[key] for r in self.data if key in r and isinstance(r[key], (int, float))]
return sum(values) / len(values) if values else None
def summary(self) -> Dict:
"""Generate data summary."""
return {
"total_records": len(self.data),
"fields": list(self.data[0].keys()) if self.data else [],
}
# === Tests ===
class TestDataProcessor(unittest.TestCase):
def setUp(self):
self.sample_data = [
{"name": "Alice", "dept": "Engineering", "salary": 95000},
{"name": "Bob", "dept": "Marketing", "salary": 75000},
{"name": "Charlie", "dept": "Engineering", "salary": 105000},
{"name": "Diana", "dept": "Marketing", "salary": 82000},
{"name": "Eve", "dept": "Engineering", "salary": 98000},
]
self.processor = DataProcessor(self.sample_data)
def test_filter_by_dept(self):
eng = self.processor.filter_by("dept", "Engineering")
self.assertEqual(len(eng), 3)
def test_sort_by_salary(self):
sorted_data = self.processor.sort_by("salary", reverse=True)
self.assertEqual(sorted_data[0]["name"], "Charlie")
def test_aggregate(self):
counts = self.processor.aggregate("dept")
self.assertEqual(counts["Engineering"], 3)
self.assertEqual(counts["Marketing"], 2)
def test_average_salary(self):
avg = self.processor.average("salary")
self.assertAlmostEqual(avg, 91000, places=0)
def test_summary(self):
summary = self.processor.summary()
self.assertEqual(summary["total_records"], 5)
def test_empty_data(self):
empty = DataProcessor([])
self.assertIsNone(empty.average("salary"))
self.assertEqual(empty.summary()["total_records"], 0)
# Run tests
print("=== Running Tests ===")
suite = unittest.TestLoader().loadTestsFromTestCase(TestDataProcessor)
unittest.TextTestRunner(verbosity=2).run(suite)
# Demo usage
print("\n=== Data Analysis ===")
processor = DataProcessor([
{"name": "Alice", "dept": "Engineering", "salary": 95000},
{"name": "Bob", "dept": "Marketing", "salary": 75000},
{"name": "Charlie", "dept": "Engineering", "salary": 105000},
{"name": "Diana", "dept": "Marketing", "salary": 82000},
{"name": "Eve", "dept": "Engineering", "salary": 98000},
])
print(f"Summary: {processor.summary()}")
print(f"Dept counts: {processor.aggregate('dept')}")
print(f"Avg salary: ${processor.average('salary'):,.0f}")
print(f"Top earners:")
for emp in processor.sort_by("salary", reverse=True)[:3]:
print(f" {emp['name']}: ${emp['salary']:,}")Tip
Tip
Combine debugging, testing, profiling, and linting into a complete development workflow. Automate everything you can.
Diagram
Loading diagram…
pytest > unittest. Use fixtures for DRY. Mock external services. Run in CI with tox for multi-version.
Common Mistake
Warning
Not writing tests for bug fixes. Every bug fix should include a test that reproduces the bug — prevents regressions.
Quick Quiz
Practice Task
Note
(1) Build a tested module with 90%+ coverage. (2) Add logging and profiling. (3) Set up a complete CI pipeline.