Open skellet0r opened 3 years ago
able to recreate on v1.13.1
original code from the blog does have an issue confusing the receiver
and to
variables, but this has been resolved in the code posted above, and is not causing the specified error.
assert len(accounts) > 0
after the import statements shows accounts
is empty which is why it fails IndexError
_______________________ ERROR collecting tests/test_transfer_hypothesis2.py ________________________
tests/test_transfer_hypothesis2.py:5: in <module>
assert len(accounts) >0
E assert 0 > 0
E + where 0 = len(<brownie.network.account.Accounts object at 0x7f0d9ac16c70>)
Since the following test passes for me, I can conclude that accounts
is empty when being fed to strategy
within the @given
decorator, but is populated when being fed to the function. I can also conclude that other than this, the test is working to exclude the listed value.
#!/usr/bin/python3
from brownie import accounts
from brownie.test import given, strategy
@given(
receiver=strategy('address', exclude='0x66aB6D9362d4F35596279692F0251Db635165871'), # this is accounts[0]
amount=strategy('uint256', max_value=10**18),
)
def test_transfer_adjusts_receiver_balance(accounts, token, receiver, amount):
balance = token.balanceOf(receiver)
token.transfer(receiver, amount, {'from': accounts[0]})
assert receiver != accounts[0]
assert token.balanceOf(receiver) == balance + amount
I was able to get this code successfully running by modifying as follows:
#!/usr/bin/python3
from brownie import accounts
from brownie.test import given, strategy
def test_transfer_adjusts_receiver_balance(accounts, token):
@given(
receiver=strategy('address', exclude=accounts[0]),
amount=strategy('uint256', max_value=10**18),
)
def run(accounts, token, receiver, amount):
balance = token.balanceOf(receiver)
token.transfer(receiver, amount, {'from': accounts[0]})
assert receiver != accounts[0]
assert token.balanceOf(receiver) == balance + amount
run(accounts, token)
The accounts
object is not loaded up until pytest
initializes brownie
, which doesn't happen until the function is ran. So I wrapped it in an additional function which then feeds the accounts to the hypothesis decorator.
If I modify my assertion operators I can see the code is now working.
#!/usr/bin/python3
from brownie import accounts
from brownie.test import given, strategy
from brownie import network
network.connect('development')
@given(
receiver=strategy('address', exclude=accounts[0]),
amount=strategy('uint256', max_value=10**18),
)
def test_transfer_adjusts_receiver_balance(accounts, token, receiver, amount):
balance = token.balanceOf(receiver)
token.transfer(receiver, amount, {'from': accounts[0]})
assert receiver != accounts[0]
assert token.balanceOf(receiver) == balance + amount
this code works, now need to see if I can inject network.connect('development')
as a lambda
function, possibly in given
, or possibly as a fixture?
I'm able to get it to work by placing brownie.network.connect('development')
within the tests\conftest.py
I am still getting the error when I try to move the line to anywhere within brownie\test\strategies.py
or brownie\test\__init__.py
both within and outside of the address strategy function.
Took a look at this.. As you said, the problem is that test collection happens prior to connecting to the network, so accounts
is empty.
Connecting to the network is handled in pytest_collection_finish
, in brownie/test/runner.py
, line 258. This is a deliberate design choice for 2 reasons:
ganache-cli
to launch and be killed.There is no easy solution I can see here unfortunately, as the call to strategy
happens immediatly upon importing the test module. A hacky solution might be to allow Accounts
to return a sort-of proxy "promise" object that represents the eventual Account
that will exist at index 0
once the network has connect. The first attempt to inspect this object would then mutate it into the actual account object, or raise if the index is out of bounds.
I was hoping to find a solution which would wrap this for the user so that they don't have to worry about it, however it seems that it's functioning as designed and so this won't be feasible? If this is the case, alternatively could we just modify the documentation for the address
strategy in order to notate that it requires loading the accounts object first?
I experienced the same problem in my test suite and found a clean workaround by altering what I am parameterizing. Instead of passing the account in the strategy, I passed the index of the account, after which I obtain the actual account through its index.
Environment information
brownie
Version: 1.12.3, 1.12.2, 1.12.1ganache-cli
Version: 6.12.1solc
Version: 0.8.0+commit.c7dfd78e.Linux.g++What was wrong?
Command:
brownie test
Code that caused failure:Error output:
Extra Information
accounts[:1]
), the IndexError doesn't get raised, however, the elementaccounts[0]
is included in the sampling. This makes sense, because a slice of an empty list, will return an empty list, which is essentially excluding nothing.