Unit Testing

  • create python test files in tests folder.

  • filenames must begin with test_

  • from brownie import <contract_name>, accounts

In this following example, we want to test that favNum initializes to 0.

  • deploy the contract

  • retrieve the starting value

  • compare it with expected starting value

from brownie import SimpleStorage, accounts

def test_deploy():
    # Arrange - setup
    account = accounts[0]

    # Act
    simple_storage = SimpleStorage.deploy({"from": account})
    starting_value = simple_storage.retrieve()
    expected_value = 0

    # Assert
    assert expected_value == starting_value

To run this test, input: brownie test in terminal:

If we get a green dot at the end like above, all tests were successful.

Test updating storage variable

  • deploy contract

  • update favNum storage variable to be 15

  • retrieve storage variable and compare with expected.

Tips

To test 1 function

brownie test -k <function name> brownie test -k test_update_storage

To get into interactive mode:

brownie test --pdb

when a test fails, or an error is encountered, terminal will convert to an interactive python shell:

we can observe the values of variables by typing them in and their values will be returned.

reference the other brownie flags from pytest documentation

get accounts

Negative tests

Lets say you want to do a test that results in a revert. Like testing a function that only the owner can call, but calling it from a non-owner address.

We will use pytest to skip tests that we only want conducted in our private local chains (pip install pytest)

You would expect a revert to be thrown, like below, reflecting that an exception had occurred:

exception thrown

How can we conduct a negative test properly?

the correct form of the test would be:

Where should i run my tests

  1. Brownie Ganache chain with Mocks: Always

    1. (tests should clear on brownie spun up ganache-cli env)

  2. Testnet: Always (but only for integration testing)

  3. Brownie mainnet-fork: Optional

  4. Custom mainnet-fork: Optional

  5. Self/Local Ganache: Not necessary, but good for tinkering

Last updated