3

I have a contract that inherits from Ownable, and some of its functions use onlyOwner modifier. I use truffle for local deployments to Ganache and testing.

Say, I have a contract:

contract MyContract is Ownable {
    function DoSomething() public view onlyOwner { return 1; }
}

A unit test for this contract is:

contract TestMyContract {
    MyContract c = MyContract(DeployedAddresses.CertifyingAgencies());
    function testDoSomething() {
        Assert.equal(c.DoSomething(), 1, "Shoudl equal 1");
    }
}

This test fails - onlyOwner modifier throws because msg.sender inside that modifier will be the address of the test contract, not the address of the owner/deployer.

How do I test such functions?

2 Answers 2

2

I've written test.js to show the example of how you can test this modifier:

var MyContract = artifacts.require("MyContract")

contract('MyContract', (accounts) => {

  let instance
  let owner = accounts[0]
  let account = accounts[1]

  beforeEach(async () => {
    instance = await MyContract.deployed()
  })

  it("should check restriction", async () => {
    try {
      let result = await instance.restrictedFunction.call({from: account})
      assert.equal(result.toString(), owner)
    } catch (e) {
      console.log(`${account} is not owner`)
    }
  })
})

In this example the test will not fail in both cases; I made it this way because it depends what result you are willing to get from this particular test. If you want it to fail if account is not owner, make this edit:

} catch (e) {
      assert.fail(null, null, `${account} is not owner`)
}
8
  • Thank you Roman, but I was trying to write this test in Solidity, not js - is that possible in this case? Also, if i do write it in JS, how do i call a transaction? Say, DoSomething function modified the storage, so it requires a real ethereum transaction - how do i do that?
    – Andrey
    Feb 6, 2018 at 19:05
  • @Andrey in js you normally use await instance.restrictedFunction.call({from: account}) and the returned value will be a tx object. In this case it will be convinient to trigger some event inside the method and read it from returned tx object by reading the logs. Feb 6, 2018 at 19:10
  • Could you elaborate on that? My methods do have events in them, but how do i read arguments of that triggered event from the tx object?
    – Andrey
    Feb 6, 2018 at 19:13
  • @Andrey I am not sure how to implement this in Solidity because there will be revert exception raised. I will come back to this question if I'll figure it out. Feb 6, 2018 at 19:14
  • Basically, what i need to test: i call a contract function that inserts a value in a mapping storage, and after that i call another function that retrieves that value to make sure it's stored.
    – Andrey
    Feb 6, 2018 at 19:15
1

My proposition for testing the following function :

function RemovePlayer(address _address) public onlyadmin returns (bool).

is

 it("Only admin can remove players", async function() {
        let Error;
await Cp.AddPlayer("player1",123,{ from: accounts[1]});

try {
     await Cp.RemovePlayer(accounts[1], {from: accounts[2]  });
        } catch (error) {
            Error = error;
;
        }
        assert.notEqual(Error, undefined, 'Exception thrown');
        assert.isAbove(Error.message.search('VM Exception while processing transaction: revert'), -1, 'Error: VM Exception while processing transaction: revert');

    });

the important part is the the assertion in the catch. As we expect : Error: VM Exception while processing transaction: revert message we can harness it to check if the modifier onlyadmin is throwing errors or not.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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