testing-with-lexigram
Skill1 starsChanged 3 months agoMITView on GitHub
Use when writing tests, creating test environments, or using stubs/fakes in the Lexigram framework
In this repository17 other files it gives its agents.
- ai-subsystem-quickstartSkill
- auth-and-securitySkill
- caching-patternsSkill
- cli-code-generationSkill
- cli-config-and-inspectSkill
- cli-database-operationsSkill
- cli-project-scaffoldingSkill
- configuration-managementSkill
- creating-providers-and-modulesSkill
- database-repository-patternSkill
- events-and-messagingSkill
- lexigram-uiSkill
- multimedia-generationSkill
- real-time-webSkill
- resilience-patternsSkill
- using-result-and-error-codesSkill
- web-controllers-and-routingSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 52
Every extension package should define stub() returning a DynamicModule with in-memory/noop backends.
- Distinctive: line 107
No global state — each test is independent
- Very specific: line 132
Not passing overrides via extra_registrations to TestEnvironment
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Testing with Lexigram
Overview
Lexigram's DI container makes testing straightforward: fake at the contract boundary, use TestEnvironment for isolation, and use stub() modules for full integration tests.
TestEnvironment
from lexigram.testing import TestEnvironment
from lexigram.testing.fakes import FakeCache
from lexigram.contracts.infra.cache import CacheBackendProtocol
async def test_user_service():
# extra_registrations is a callable receiving the container
env = TestEnvironment(
extra_registrations=lambda c: c.singleton(
CacheBackendProtocol, instance=FakeCache()
)
)
await env.setup()
service = await env.container.resolve(UserService)
result = await service.get_user("user-123")
assert result.is_ok()
await env.teardown()Each TestEnvironment is fully isolated — no global state pollution.
Module Stubs
@module(imports=[
LLMModule.stub(), # No-op LLM
EventsModule.stub(), # In-memory events
DatabaseModule.stub(), # In-memory DB
])
class TestModule(Module): pass
async def test_with_modules():
async with Application.boot(modules=[TestModule]) as app:
service = await app.container.resolve(MyService)
result = await service.process()
assert result.is_ok()Every extension package should define stub() returning a DynamicModule with in-memory/noop backends.
Testing Result-Returning Methods
@pytest.mark.asyncio
async def test_find_user_returns_ok():
result = await service.find_user("user-123")
assert result.is_ok()
assert result.unwrap().id == "user-123"
@pytest.mark.asyncio
async def test_find_user_returns_err():
result = await service.find_user("nonexistent")
assert result.is_err()
assert isinstance(result.unwrap_err(), UserNotFound)Ambient Clock Override
from datetime import UTC, datetime
from lexigram.testing import FixedClock
from lexigram.primitives import clock
# FixedClock requires a timezone-aware datetime
with clock.use(FixedClock(datetime(2026, 1, 1, tzinfo=UTC))):
assert clock.now().year == 2026Test Organization
# tests/test_user_service.py
class TestUserService:
@pytest.fixture
def mock_db(self) -> AsyncMock:
db = AsyncMock(spec=DatabaseProviderProtocol)
db.execute = AsyncMock(return_value=[])
return db
@pytest.mark.asyncio
async def test_create_user(self, mock_db: AsyncMock) -> None:
service = UserService(db=mock_db)
user = await service.create(email="test@example.com")
assert user.id is not None
mock_db.execute.assert_awaited_once()Conventions
- Files:
test_*.py - Classes:
Test* - Methods:
test_* - Fakes at contract boundary — mock
Protocol, not internals - No global state — each test is independent
- Mock clients in
tests/, never insrc/
Running Tests
uv run pytest # Full suite
uv run pytest -m "not integration" # Unit-only
uv run pytest -m integration # Integration only
uv run pytest lexigram-web/tests/ # Single package
uv run pytest -k "test_user" # Pattern match
uv run pytest --cov --cov-report=html # Coverage
uv run pytest --cov-fail-under=80 # Coverage gatePytest Markers
Defined in root pyproject.toml: integration, slow, unit, e2e, scenario, performance, plus requires_* markers: redis, postgres, elasticsearch, meilisearch, rabbitmq, smtp, kafka, minio, mongodb, qdrant, neo4j.
Common Mistakes
- Testing with real infrastructure (DB, Redis) for unit tests — use stubs
- Forgetting
@pytest.mark.asyncioon async tests - Mocking implementation details instead of protocol interfaces
- Shared global state between tests — use fresh
TestEnvironmentper test - Not passing overrides via
extra_registrationstoTestEnvironment - Testing without
stub()modules — forces full boot with real infrastructure
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

