Package: pytest-cairo
pytest-cairo: pytest support for cairo-lang and starknetUsageTo install:$pipinstallpytest-cairoThe plugin will automatically run any function with atestprefix, from files with atest_prefix and a.cairoextension.ExamplesBasic testsConsider the following Starknet contract:# Contents of contract.cairo
%lang starknet

from starkware.cairo.common.cairo_builtins import HashBuiltin

func calculate_inverse{
    syscall_ptr : felt*,
    pedersen_ptr : HashBuiltin*,
    range_check_ptr,
}(val : felt) -> (res : felt):
    return (1 / val)
endWe could write a basic test for the functioncalculate_inverse:# Contents of test_contract.cairo
%lang starknet

from starkware.cairo.common.cairo_builtins import HashBuiltin

from contracts.contract import calculate_inverse

@external
func test_calculate_inverse{
    syscall_ptr : felt*,
    pedersen_ptr : HashBuiltin*,
    range_check_ptr,
}() -> ():
    let (actual) = calculate_inverse(2)
    let expected = 1 / 2
    assert actual = expected
    return ()
endAdditionally we could use araisesattribute to assert that the function fails if we passval=0:@external
func test_calculate_inverse_expected_exception{
    syscall_ptr : felt*,
    pedersen_ptr : HashBuiltin*,
    range_check_ptr,
}() -> ():
    with_attr raises("assert_not_zero failed"):
        calculate_inverse(0)
    end
    return ()
endDeploying contractsContracts can be deployed from tests using thedeploy_contracthelper function. Consider the same contract from the previous example, but extended with a constructor:# Contents of contracts/contract.cairo
%lang starknet

from starkware.cairo.common.cairo_builtins import HashBuiltin

@constructor
func constructor{
    syscall_ptr : felt*,
    pedersen_ptr : HashBuiltin*,
}(arg : felt):
    return ()
end

func calculate_inverse{
    syscall_ptr : felt*,
    pedersen_ptr : HashBuiltin*,
    range_check_ptr,
}(val : felt) -> (res : felt):
    return (1 / val)
endWe can deploy this contract in ourtest_contractfunction and call its methods:%lang starknet

from starkware.cairo.common.alloc import alloc
from starkware.cairo.common.cairo_builtins import HashBuiltin

from contracts.interfaces.IContract import IContract

from pytest_cairo.contract_index import contracts
from pytest_cairo.helpers import deploy_contract

@view
func test_contract{
    syscall_ptr : felt*,
    pedersen_ptr : HashBuiltin*,
    range_check_ptr,
}() -> ():

    let (calldata : felt*) = alloc()
    assert calldata[0] = 1  # Value is not relevant
    let (contract_address) = deploy_contract(contracts.contract, 1, calldata)

    let (result) = IContract.calculate_inverse(
        contract_address=contract_address, val=4)

    assert result = 1/4

    return ()
endThecontract_indexprovides a reference to contracts and is generated automatically by indexing folders that contain.cairofiles in the current working directory. In the above example the contractcontract.cairois located in a folder calledcontracts, so we can reference it ascontracts.contract.Other helper functionsOther available helper functions:set_block_number: sets the current block numberset_block_timestamp: sets the current block timestampset_caller_address: sets the caller address returned byget_caller_addressset_contract_address: sets the contract address of the current test contract. This is useful when calling other contracts, since this address will be returned when the other contract callsget_caller_addressimpersonate: sets both the caller address and the contract address. The former is useful when testing functions directly, the latter when calling functions in other contractsHelper functions can be imported frompytest_cairo.helpers.FixturesFixtures work similarly to regular pytest fixtures: functions can be marked as fixtures using the@fixturedecorator. Tests can then request a fixture's result by referencing the fixture name as an argument. A basic example:%lang starknet


@view
@fixture
func my_fixture() -> (fixture_return_value : felt):
    return (fixture_return_value=999)
end


@view
func test_fixture_usage(my_fixture : felt) -> ():

    assert my_fixture = 999

    return ()
endNote:Fixtures can only return a single value. Use a struct if multiple values have to be returned.Fixtures aremodulescope, i.e. they are executed once for each test module and the result is cached. Iffunctionscope is required, consider calling the function directly.If a fixture is not meant to return any value, the argument in the test function should be annotated as afelt(a default value of0will be passed).DevelopmentTo install development dependencies, run:$pipinstall-rrequirements-dev.txtRun tests with:$pytestor:$docker-composeruntestTo run tests against all supported interpreters (usingdocker-compose):$toxThis assumestox,dockeranddocker-composeare installed.