Example Tests¶
Putting testing ideas into practice¶
This page shows larger, more realistic examples that build on the
concepts introduced in the Testing guide.
The focus here is on observable behavior, not on testing the toolkit itself.
1. Composing behavior with Result¶
from forging_blocks.foundation import Result, Ok, Err
def parse_int(value: str) -> Result[int, str]:
try:
return Ok(int(value))
except ValueError:
return Err(f"invalid integer: {value!r}")
def reciprocal(value: int) -> Result[float, str]:
if value == 0:
return Err("division by zero")
return Ok(1 / value)
def parse_reciprocal(raw: str) -> Result[float, str]:
result = parse_int(raw)
if result.is_err:
return result
match result:
case Ok(value):
return reciprocal(value)
Tests¶
from your_module import parse_reciprocal
def test_parse_reciprocal_when_valid_input_then_succeeds() -> None:
result = parse_reciprocal("4")
assert result.is_ok
def test_parse_reciprocal_when_invalid_input_then_fails() -> None:
result = parse_reciprocal("foo")
assert result.is_err
def test_parse_reciprocal_when_zero_then_fails() -> None:
result = parse_reciprocal("0")
assert result.is_err
2. Testing a simple use case¶
from dataclasses import dataclass
from forging_blocks.application import UseCase
from forging_blocks.foundation import Result, Err
@dataclass
class CreateTaskInput:
title: str
class TaskRepository:
def save(self, title: str) -> Result[int, str]:
...
class CreateTaskUseCase(UseCase):
def execute(self, data: CreateTaskInput) -> Result[int, str]:
...
class CreateTaskService(CreateTaskUseCase):
def __init__(self, repo: TaskRepository) -> None:
self._repo = repo
def execute(self, data: CreateTaskInput) -> Result[int, str]:
if not data.title.strip():
return Err("title required")
return self._repo.save(data.title)
Fake repository¶
from forging_blocks.foundation import Result, Ok
class InMemoryTaskRepository:
def __init__(self) -> None:
self.tasks: dict[int, str] = {}
self._next_id = 1
def save(self, title: str) -> Result[int, str]:
for task_id, existing in self.tasks.items():
if existing == title:
return Ok(task_id)
task_id = self._next_id
self._next_id += 1
self.tasks[task_id] = title
return Ok(task_id)
Tests¶
from your_module import CreateTaskService, CreateTaskInput, InMemoryTaskRepository
def test_create_task_when_valid_title_then_succeeds() -> None:
repo = InMemoryTaskRepository()
service = CreateTaskService(repo)
result = service.execute(CreateTaskInput(title="Write docs"))
assert result.is_ok
assert len(repo.tasks) == 1
def test_create_task_when_duplicate_title_then_reuses_task() -> None:
repo = InMemoryTaskRepository()
service = CreateTaskService(repo)
first = service.execute(CreateTaskInput(title="Write docs"))
second = service.execute(CreateTaskInput(title="Write docs"))
assert first.is_ok
assert second.is_ok
assert len(repo.tasks) == 1
def test_create_task_when_missing_title_then_fails() -> None:
repo = InMemoryTaskRepository()
service = CreateTaskService(repo)
result = service.execute(CreateTaskInput(title=" "))
assert result.is_err
Key takeaway¶
Tests should describe what happened, not how the toolkit represents it.
Use pattern matching when you need data.
Otherwise, assert success or failure and move on.