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
gltest.config.yaml– Configures the RPC endpoint (http://127.0.0.1:8545) and default account credentials for the test suite.tests/integration/fixtures.py– Contains reusable state definitions and common setup logic imported viaload_fixture.tests/integration/test_football_bets.py– Full implementation showing deployment patterns and assertion strategies for theFootballBetscontract.contracts/football_bets.py– The smart contract under test exposing methods likecreate_bet,resolve_bet,get_points, andget_player_points.
Summary
- gltest provides a Python framework for integration testing GenLayer smart contracts against a live Studio node.
- Configure connection settings in
gltest.config.yamland usedefault_accountas 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.pyand loading them withload_fixture. - Assert transaction success using
tx_execution_succeededfromgltest.assertions. - Handle asynchronous external API calls within contracts using
wait_intervalandwait_retriesparameters.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →