Benefits of Direct Mode Testing in GenLayer: A Complete Developer Guide
Direct mode testing in GenLayer executes intelligent contracts entirely in-memory without launching a GenLayer Studio instance, delivering millisecond-fast feedback loops while supporting full contract API coverage and deterministic validation of nondeterministic web and LLM calls.
Direct mode testing serves as the primary unit-testing layer for the genlayerlabs/genlayer-project-boilerplate repository. This approach allows developers to validate GenLayer intelligent contract logic locally using the nondeterministic-aware SDK, eliminating external service dependencies during the development cycle while exercising production code paths.
What Is Direct Mode Testing in GenLayer?
Direct mode testing runs GenLayer intelligent contracts in a local virtual machine without requiring a running GenLayer Studio instance or deployed contracts. Unlike integration tests that spin up containers or connect to live networks, direct mode loads the Python contract class directly into memory and invokes methods against an isolated state. According to the source code in CLAUDE.md, this design provides deterministic control over nondeterministic operations while maintaining byte-for-byte compatibility with the code paths executed in a full Studio deployment.
Seven Core Benefits of Direct Mode Testing
Instant In-Memory Execution
Tests start and finish in milliseconds because the contract loads directly into a local VM without network or VM startup latency. As documented in the README.md, this architecture removes the overhead of container orchestration, allowing developers to iterate rapidly on contract logic.
Zero Studio Dependency
You do not need a running GenLayer Studio instance or deployed contracts to execute the full test suite. All contract logic exercises locally, which removes external service requirements during most development cycles. This independence makes direct mode testing ideal for offline development and rapid prototyping.
Built-in Mocking for Nondeterministic Calls
The direct_vm fixture provides mock_web and mock_llm methods that control responses from gl.nondet.web and gl.nondet.exec_prompt calls. Even contracts that scrape web data or parse LLM outputs can run deterministically in tests—you supply expected payloads and verify handling without external API calls.
Complete Contract API Coverage
Direct mode supports calling any public view or write method, setting the transaction sender via direct_vm.sender, and inspecting storage exactly as in a real deployment. The same Python contract class used in direct mode runs in Studio, ensuring identical code paths between test and production environments.
Precise Revert Verification
Use direct_vm.expect_revert to assert that transactions fail with specific revert messages. This guarantees that contract validation logic—such as duplicate-bet checks in contracts/football_bets.py—works as intended without silent failures.
Isolated and Repeatable Test States
The direct_vm.clear_mocks method and the ability to redeploy contracts per test keep each test sandboxed. This isolation prevents side-effects from one test from affecting another, making the suite reliable and parallelizable.
Fast CI Integration
Because individual tests execute in less than a millisecond, they integrate seamlessly into continuous integration pipelines. The repository's .github/workflows/ci.yml runs direct tests on every push, providing immediate feedback on pull requests without the resource overhead of full Studio deployments.
Implementing Direct Mode Tests: Code Examples
Deploying and testing a contract in direct mode requires the direct_vm, direct_deploy, and account fixtures provided by tests/direct/conftest.py.
Basic Contract Deployment and State Verification
def test_create_bet(direct_vm, direct_deploy, direct_alice):
# Deploy the contract in-memory
contract = direct_deploy("contracts/football_bets.py")
# Set the transaction sender
direct_vm.sender = direct_alice
# Call a write method
contract.create_bet("2024-06-20", "Spain", "Italy", "1")
# Verify storage via a view method
bets = contract.get_bets()
alice = direct_alice.as_hex # helper from tests/direct/conftest.py
assert "2024-06-20_spain_italy" in bets[alice]
Mocking Web and LLM Calls
def test_resolve_bet_with_mocks(direct_vm, direct_deploy, direct_alice):
contract = direct_deploy("contracts/football_bets.py")
direct_vm.sender = direct_alice
contract.create_bet("2024-06-20", "Spain", "Italy", "1")
# Mock the HTTP request the contract will make
direct_vm.mock_web(
r"https://www.bbc.com/sport/football/scores-fixtures/2024-06-20",
{"status": 200, "body": "<html>…Spain 2-1 Italy…</html>"}
)
# Mock the LLM response that parses the score
direct_vm.mock_llm(
r".*Extract the final score.*",
'{"score": "2-1"}'
)
# Resolve the bet (non-deterministic code path)
contract.resolve_bet("2024-06-20", "Spain", "Italy")
# Assert the final state
bet = contract.get_bets()[direct_alice.as_hex]["2024-06-20_spain_italy"]
assert bet.real_score == "2-1"
assert bet.has_resolved is True
Asserting Expected Reverts
def test_invalid_duplicate_bet_fails(direct_vm, direct_deploy, direct_alice):
contract = direct_deploy("contracts/football_bets.py")
direct_vm.sender = direct_alice
contract.create_bet("2024-06-20", "Spain", "Italy", "1")
# Expect the contract to revert on a duplicate bet
with direct_vm.expect_revert("Bet already created"):
contract.create_bet("2024-06-20", "Spain", "Italy", "2")
Key Source Files in the Boilerplate
Understanding the repository structure helps locate relevant test utilities and examples:
contracts/football_bets.py– Example intelligent contract demonstrating web scraping and LLM integrationtests/direct/conftest.py– Pytest fixtures includingto_hexhelpers and VM initializationtests/direct/test_create_bet.py– Direct-mode test for bet creation logic without external mockstests/direct/test_resolve_bet.py– Direct-mode test demonstratingmock_webandmock_llmusageREADME.md– Development workflow documentation covering direct-mode executionCLAUDE.md– Detailed SDK guidance for writing direct-mode tests.github/workflows/ci.yml– GitHub Actions workflow executing direct tests on every push
Summary
- Direct mode testing executes GenLayer contracts in-memory without Studio dependencies, providing millisecond-fast feedback.
- Mock utilities (
direct_vm.mock_web,direct_vm.mock_llm) make nondeterministic operations deterministic and testable. - Full API coverage includes sender impersonation, state inspection, and precise revert assertions via
direct_vm.expect_revert. - Isolated environments ensure tests remain independent and parallelizable through per-test deployments and
clear_mocks. - CI-ready performance allows the test suite to run on every commit in
.github/workflows/ci.ymlwithout infrastructure overhead.
Frequently Asked Questions
How does direct mode testing differ from Studio testing in GenLayer?
Direct mode testing runs contracts in a local Python VM without network latency or container startup, while Studio testing requires a running GenLayer Studio instance with full node simulation. Direct mode targets unit testing with mocked dependencies, whereas Studio testing validates integration with the actual consensus and networking layers.
Can I test contracts that use LLM and web calls in direct mode?
Yes. Use direct_vm.mock_web to intercept HTTP requests made via gl.nondet.web and direct_vm.mock_llm to control responses from gl.nondet.exec_prompt. This allows deterministic testing of contracts that normally rely on external APIs, as demonstrated in tests/direct/test_resolve_bet.py.
How do I set the transaction sender in direct mode tests?
Assign an address to direct_vm.sender before invoking contract methods. The test fixtures in tests/direct/conftest.py provide predefined accounts like direct_alice that expose an as_hex property for easy assignment to the sender attribute.
Is direct mode testing suitable for CI/CD pipelines?
Yes. Because direct mode tests execute in milliseconds without Docker containers or external services, they integrate efficiently into CI pipelines. The genlayer-project-boilerplate repository runs these tests in .github/workflows/ci.yml on every push to provide immediate build feedback.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →