6

I'm using https://github.com/dapphub/dapp framework for writing Solidity contracts and their ds-test unit test framework.

Has anyone tried to cover modifiers in unit tests? Example:

    modifier onlyOwner {
        if (msg.sender != owner) throw;
        _;
    }
1

Yes, there is, perhaps a better way to phrase this is how to test for throw conditions - or now, rather assert(), require(), and revert(). For example, in the case above, you want to make sure that when someone other than the owner calls a function, then the function throws and any state changes are rolled back to their original state. The best way to do this is with Solidity unit tests using Truffle. Unfortunately, when using JavaScript unit tests, when a throw condition is encountered, then the test "breaks" - with Solidity unit tests, you can test many throw conditions at the same time without stopping.

What you will want to use is a proxy contract to “to wrap the contract call to a raw call and return whether it succeeded or not.”. A proxy contract should look like the below:

contract ThrowProxy {
  address public target;
  bytes data;

  function ThrowProxy(address _target) {
    target = _target;
  }

  //prime the data using the fallback function.
  function() {
    data = msg.data;
  }

 function execute() returns (bool) {
    return target.call(data);
  }
}

In the creation of your throwProxy contract, your _target would be the address of the contract that you would like to test.

In your Solidity unit test, you would include a test like the below:

function testTheThrow() {
    MyContract mycontract = new MyContract(); 
    ThrowProxy throwproxy = new ThrowProxy(address(mycontract)); 
    MyContract(address(throwproxy)).functionThatShouldThrow();
    bool r = throwproxy.execute.gas(200000)(); 
    Assert.isFalse(r, "Should be false because is should throw!");
}

In the example above, we are using the fallback function from the throwProxy contract to compile the call data to execute the functionThatShouldThrow() by using the execute() function from the throwProxy to use the .call() method on your original target, MyContract. Recall that .call() return a Boolean as to whether execution is successful or not - it does not include any returns from the function. From here, saving the r as to the Boolean value as to whether the functionThatShouldThrow() is successful or not. From here, you can use the Assert.sol library to assert that r is in fact false because the function should have thrown.

0

Whether function uses modifier or just performs necessary checks in its body is internal implementation details of the function that are not visible from outside. So tests should not care about this. If some function should only be callable by the owner of the smart contract, write a test that calls the function from both, owner and non-owner accounts, and checks that the requirement is fulfilled. This way your test will work regardless of whether modifier is used or check is performed in function body.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.