How to Perform Integration Testing with gltest in GenLayer

Integration tests in GenLayer use the gltest framework to deploy smart contracts to a local Studio node and assert end-to-end behavior, ensuring that transactions, state changes, and external API interactions work correctly in a live environment.

Integration testing with gltest in GenLayer validates the complete execution flow of smart contracts against a running GenLayer Studio instance. Unlike mocked unit tests, this approach executes real transactions through the gltest helper library, confirming that contract deployment, method calls, and state transitions function exactly as they would in production.

Configuring the gltest Environment

Before running tests, configure the connection parameters in gltest.config.yaml. This file defines the RPC endpoint and default account used across all test executions.

By default, gltest targets a local Studio node at http://127.0.0.1:8545. The configuration also specifies the default account—typically the first pre-funded test address—that serves as the transaction sender for all contract interactions.


# gltest.config.yaml

rpc_url: http://127.0.0.1:8545
default_account: "0x..."

The gltest Architecture for Integration Testing

Contract Factory Pattern

The get_contract_factory("ContractName") function returns a factory object capable of deploying fresh contract instances. According to the source code in genlayerlabs/genlayer-project-boilerplate, each test should deploy its own contract to ensure complete isolation.

from gltest import get_contract_factory

factory = get_contract_factory("FootballBets")
contract = factory.deploy()

Fixture Reuse with load_fixture

Common setup logic resides in tests/integration/fixtures.py. The load_fixture helper imports these reusable components, allowing multiple tests to share deployment code without duplication.

from gltest.helpers import load_fixture
from tests.integration.fixtures import football_bets_win_unresolved

contract = load_fixture(deploy_contract)

Pre-funded Test Accounts

gltest.default_account provides a pre-funded address that acts as the signer for all transactions. This account is automatically configured with sufficient balance to cover gas costs during test execution.

from gltest import default_account

sender_address = default_account.address

Writing End-to-End Integration Tests

Deploying Contract Instances

Each test method should deploy a fresh contract instance to prevent state pollution between test cases. The deployment returns a contract object with methods corresponding to the smart contract functions defined in files like contracts/football_bets.py.

@pytest.mark.integration
def deploy_contract():
    factory = get_contract_factory("FootballBets")
    contract = factory.deploy()
    assert contract.get_points(args=[]) == {}
    return contract

Executing Write Transactions

Invoke contract methods using the deployed contract object. Pass arguments as a list to the args parameter. Write operations return transaction objects that can be inspected for success status.

tx = contract.create_bet(args=["2024-06-20", "Spain", "Italy", "1"])

Asserting Transaction Success

The tx_execution_succeeded assertion helper from gltest.assertions verifies that a transaction did not revert and that gas was consumed as expected.

from gltest.assertions import tx_execution_succeeded

assert tx_execution_succeeded(tx)

Handling Nondeterministic Operations

For methods that call external web APIs (such as resolve_bet), use the wait_interval and wait_retries parameters to poll for completion. This handles the asynchronous nature of real-world data fetches within the contract.

resolve_tx = contract.resolve_bet(
    args=["2024-06-20_spain_italy"],
    wait_interval=10_000,  # milliseconds between retries

    wait_retries=15
)
assert tx_execution_succeeded(resolve_tx)

Complete Integration Test Example

The file tests/integration/test_football_bets.py demonstrates the full workflow: deploying a contract, creating a bet, resolving it via external API, and verifying state changes.

import pytest
from gltest import get_contract_factory, default_account
from gltest.helpers import load_fixture
from gltest.assertions import tx_execution_succeeded
from tests.integration.fixtures import football_bets_win_unresolved, football_bets_win_resolved

@pytest.mark.integration
def deploy_contract():
    factory = get_contract_factory("FootballBets")
    contract = factory.deploy()
    assert contract.get_points(args=[]) == {}
    assert contract.get_bets(args=[]) == {}
    return contract

@pytest.mark.integration
def test_football_bets_success_win():
    contract = load_fixture(deploy_contract)

    # Create a bet

    tx = contract.create_bet(args=["2024-06-20", "Spain", "Italy", "1"])
    assert tx_execution_succeeded(tx)

    # Verify initial state

    assert contract.get_bets(args=[]) == {
        default_account.address: football_bets_win_unresolved
    }

    # Resolve the bet (calls external API)

    resolve_tx = contract.resolve_bet(
        args=["2024-06-20_spain_italy"],
        wait_interval=10_000,
        wait_retries=15
    )
    assert tx_execution_succeeded(resolve_tx)

    # Verify resolved state

    assert contract.get_bets(args=[]) == {
        default_account.address: football_bets_win_resolved
    }
    assert contract.get_points(args=[]) == {default_account.address: 1}
    assert contract.get_player_points(args=[default_account.address]) == 1

Key Files in the Testing Workflow

Summary

  • gltest provides a Python framework for integration testing GenLayer smart contracts against a live Studio node.
  • Configure connection settings in gltest.config.yaml and use default_account as the transaction signer.
  • Deploy fresh contract instances using get_contract_factory("ContractName").deploy() to ensure test isolation.
  • Reuse setup logic by placing common fixtures in tests/integration/fixtures.py and loading them with load_fixture.
  • Assert transaction success using tx_execution_succeeded from gltest.assertions.
  • Handle asynchronous external API calls within contracts using wait_interval and wait_retries parameters.

Frequently Asked Questions

What is gltest in GenLayer?

gltest is the official Python testing framework for GenLayer that enables integration testing by connecting to a running GenLayer Studio instance. It provides utilities for deploying contracts, executing transactions, and asserting results against actual on-chain state, differing from unit testing by validating real network interactions rather than mocked behavior.

How do I configure the Studio connection for integration tests?

Create or modify gltest.config.yaml in your project root to specify the rpc_url (default http://127.0.0.1:8545) and the default_account address. This configuration file is automatically read by gltest helpers to establish the connection and authenticate transactions during test execution.

Can I reuse contract deployment logic across multiple tests?

Yes. Place common deployment functions in tests/integration/fixtures.py, then import and invoke them using load_fixture from gltest.helpers. This pattern ensures consistent initial state while maintaining the flexibility to customize specific test scenarios without code duplication.

How do I handle external API calls in integration tests?

When testing methods like resolve_bet that fetch external data, pass wait_interval (milliseconds between polls) and wait_retries (maximum attempts) parameters to the contract method call. This polling mechanism accommodates the nondeterministic latency of real-world API requests while allowing tests to verify eventual consistency of contract state.

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 →