Skip to content

Commit

Permalink
Add documentation on how to do unit tests with web3.py
Browse files Browse the repository at this point in the history
  • Loading branch information
relyt29 committed Apr 12, 2019
1 parent f4a7d8c commit e6bfd26
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 0 deletions.
22 changes: 22 additions & 0 deletions docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -449,3 +449,25 @@ When someone has an allowance they can transfer those tokens using the


.. _ERC20: https://github.com/ethereum/EIPs/blob/7f4f0377730f5fc266824084188cc17cf246932e/EIPS/eip-20.md


Contract Unit Tests in Python
-----------------------------

Here is an example of how one can use the pytest platform in python,web3.py,
eth-tester, and pyevm to perform unit tests entirely in python without any
additional need for a full featured ethereum node/client. To install needed
dependencies you can use the pinned extra for eth_tester in web3 and pytest:

.. code-block:: bash
pip install web3[tester] pytest
Once you have an environment set up for testing, you can then write your tests
like so:

.. include:: ../tests/core/contracts/test_contract_example.py
:code: python
:start_line: 1



97 changes: 97 additions & 0 deletions tests/core/contracts/test_contract_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# This file is used by the documentation as an example of how to write unit tests with web3.py
import logging
import pytest

from web3 import (
EthereumTesterProvider,
Web3,
)


@pytest.fixture
def tester_provider():
return EthereumTesterProvider()


@pytest.fixture
def eth_tester(tester_provider):
return tester_provider.ethereum_tester


@pytest.fixture
def w3(tester_provider):
return Web3(tester_provider)


@pytest.fixture
def deploy_contract(eth_tester, w3):
# For simplicity of this example we statically define the
# contract code here. You might read your contracts from a
# file, or something else to test with in your own code
#
# pragma solidity^0.5.3;
#
# contract Foo {
#
# string public bar;
# event barred(string _bar);
#
# constructor() public {
# bar = "hello world";
# }
#
# function setBar(string memory _bar) public {
# bar = _bar;
# emit barred(_bar);
# }
#
# }

deploy_address = str(eth_tester.get_accounts()[0])

abi = """[{"anonymous":false,"inputs":[{"indexed":false,"name":"_bar","type":"string"}],"name":"barred","type":"event"},{"constant":false,"inputs":[{"name":"_bar","type":"string"}],"name":"setBar","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"constant":true,"inputs":[],"name":"bar","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]""" # noqa: E501
# This bytecode is the output of compiling with
# solc version:0.5.3+commit.10d17f24.Emscripten.clang
bytecode = """608060405234801561001057600080fd5b506040805190810160405280600b81526020017f68656c6c6f20776f726c640000000000000000000000000000000000000000008152506000908051906020019061005c929190610062565b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b6103bb806101166000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c01000000000000000000000000000000000000000000000000000000009004806397bc14aa14610058578063febb0f7e14610113575b600080fd5b6101116004803603602081101561006e57600080fd5b810190808035906020019064010000000081111561008b57600080fd5b82018360208201111561009d57600080fd5b803590602001918460018302840111640100000000831117156100bf57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610196565b005b61011b61024c565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561015b578082015181840152602081019050610140565b50505050905090810190601f1680156101885780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b80600090805190602001906101ac9291906102ea565b507f5f71ad82e16f082de5ff496b140e2fbc8621eeb37b36d59b185c3f1364bbd529816040518080602001828103825283818151815260200191508051906020019080838360005b8381101561020f5780820151818401526020810190506101f4565b50505050905090810190601f16801561023c5780820380516001836020036101000a031916815260200191505b509250505060405180910390a150565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102e25780601f106102b7576101008083540402835291602001916102e2565b820191906000526020600020905b8154815290600101906020018083116102c557829003601f168201915b505050505081565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061032b57805160ff1916838001178555610359565b82800160010185558215610359579182015b8281111561035857825182559160200191906001019061033d565b5b509050610366919061036a565b5090565b61038c91905b80821115610388576000816000905550600101610370565b5090565b9056fea165627a7a72305820ae6ca683d45ee8a71bba45caee29e4815147cd308f772c853a20dfe08214dbb50029""" # noqa: E501
contract = w3.eth.contract(abi=abi, bytecode=bytecode)
tx_hash = contract.constructor().transact({
'from': deploy_address,
'gas': 2000000
})
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash, 180)
return w3.eth.contract(abi=abi, address=tx_receipt.contractAddress)


def test_hello_world(deploy_contract):
contract_object = deploy_contract
hw = contract_object.functions.bar().call()
logging.info(hw)
assert hw == "hello world"


def test_set_bar(eth_tester, w3, deploy_contract):
contract_object = deploy_contract
account1 = str(eth_tester.get_accounts()[1])
event_filter = contract_object.events.barred().createFilter(
fromBlock='latest') # argument_filters={'args': '_bar'})

assert eth_tester.get_balance(account1) == 1000000000000000000000000

tx_hash = contract_object.functions.setBar(
"ethereum is the best").transact({
'from': account1,
'gas': 2000000
})
w3.eth.waitForTransactionReceipt(tx_hash, 180)

hw = contract_object.functions.bar().call()
assert hw == "ethereum is the best"
assert eth_tester.get_balance(
account1
) != 1000000000000000000000000 # gotta spend money on tx fees to call setBar

event_list = event_filter.get_new_entries()
assert len(event_list) == 1
event = event_list[0]
print(event)
assert event['args']['_bar'] == "ethereum is the best"

0 comments on commit e6bfd26

Please sign in to comment.