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:

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.yml without 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →