Testing

PAB comes with a pytest plugin pab.test. It allows you to test your strategies against local deployments of Smart Contracts by providing some usefull functionallity like starting a Ganache server, building and deploying your contracts with Truffle and automatically fill in some necessary/usefull info like Ganache test accounts private keys and connection endpoint, and the temporary contract addresses on the local network.

Example Use Case

Say you have a strategy that increments a counter on a Smart Contract every time it runs by calling a incrementCounter() method on the contract.

Maybe a good test would be to deploy a contract into a test network, run the strategy a couple of times and check that the counter is correctly updated. The PAB.test plugin eases this process, and allows you to easily write an automated test that you can run through pytest.

You would only need a truffle project with one contract that has a compatible ABI, this can be a Mock or even the live contract code if you have access to it.

For our example:

 1contract Counter {
 2    unit8 counter;
 3
 4    constructor() {
 5        counter = 0;
 6    }
 7
 8    function getCounter() public view returns (uint8) {
 9        return counter;
10    }
11
12    function incrementCounter () public {
13        counter += 1;
14    }
15}

Then, you can write a test like this:

 1from strategies import MyStrategy
 2
 3def test_asd(setup_project, get_strat):
 4    with setup_project() as pab:
 5        params = {"contract": "Counter"}
 6        strat: MyStrategy = get_strat(pab, 'MyStrategy', params)
 7        assert strat.vault_token.functions.getCounter().call() == 0
 8        strat.run()
 9        assert strat.vault_token.functions.getCounter().call() == 1
10        strat.run()
11        assert strat.vault_token.functions.getCounter().call() == 2

That’s it, when the plugin loads it will deploy the Counter contract into a test server and automatically register the contract with the correct test address and ABI. Counter doesn’t need to be registered as a contract name.

PAB Testing Plugin

The pab.test plugin will start a local Ganache server, test and deploy your contracts with Truffle and install some usefull fixtures for your tests.

It works in the following way:

When a pytest session is created, the plugin starts a local Ganache server by spawning a ganache-cli subprocess. It will parse the ganache startup output and collect the connection data (host, port) and the auto-generated private keys.

After the Ganache server is running, it will run truffle deploy on all directories specified in the pab-contracts-sources config (see Plugin Configuration). The output of the deployments is parsed to collect the relevant contract data. The default network for deployment is `development but it can be changed with the pab-truffle-network config. All contract sources must be valid Truffle Project.

The last thing done in initialization is to register two pytest fixtures, pab.test.setup_project() and pab.test.get_strat(). You can read more about them in the Test API.

When the pytest session finishes, the ganache process is stopped.

To use the plugin, you must manually install Ganache and Truffle, probably through npm. The plugin will check if both dependencies are installed as ganache-cli and truffle.

Test Case Example

The following is a sample test case written with the help of the PAB Testing Plugin.

 1# MyProject/tests/test_basic.py
 2def test_basic_run(setup_project, get_strat):
 3    with setup_project("MyProject") as pab:
 4        params = {
 5            "contract_a": "ABC",
 6            "contract_b": "DEF"
 7        }
 8        strat = get_strat(pab, "MyStrategyABC", params)
 9        strat.run()
10        assert strat.contract_a.functions.getSomeValue.call() == 'Some Value'

The example uses the setup_project fixture to initialize the PAB test project and return a pab.core.PAB instance. Inside the context of setup_project, the get_strat fixture is used to retrieve a single strategy from the PAB app, initialized with certain parameters. Finally executes the strategy and asserts that a side-effect (in this case, a value change on some contract attribute) happened.

Plugin Configuration

To enable the plugin you need to add pab.test to pytest_plugins in your conftest.py:

1# MyProject/tests/conftest.py
2import pytest
3pytest_plugins = ["pab.test"]

You can also change some configurations in your pytest.ini:

# MyProject/pytest.ini
[pytest]
pab-ignore-patterns-on-copy =
    venv/
pab-contracts-sources =
    tests/contracts
pab-truffle-network = development

Ganache Configuration

There’s not much configuration that’s necessary for ganache. PAB starts the process by running ganache-cli without extra parameters. By default, this starts a server in at 127.0.0.1:8545.

Truffle Configuration

The only necessary configuration for truffle is to correctly setup your network parameters. Ganache defaults are 127.0.0.1:8545, so make sure that there is a network with those parameters.

For example, in your truffle-config.js:

{
    # More configs above
    networks: {
        development: {
            host: "127.0.0.1",
            port: 8545,
            network_id: "*",
        }
    }
    # More configs below
}