Solidity – How to Change msg.sender Address and msg.value in Unit Tests

soliditytestrpctruffleunittesting

I would like to know if it's possible to change the address of the message sender of contract's function call when writing unit tests in solidity. It really should be, I was trying to find out how but could not.

pragma solidity ^0.4.4;

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";

contract A {

    event Test(address add);

    function test() {
        Test(msg.sender);
    }
}

contract TestA {

    function test01() {
        A a = A(DeployedAddresses.A());
        a.test(); // <--- msg.sender is address(this), but how do we use a different account from testrpc?
    }
}

In gitter I got a response so I have tried to run it like this:

a.test({from: 0xf6a948bff792e4f42d7f17e5e4ebe20871d160f2});

It gives the following error:

TypeError: Wrong argument count for function call: 1 arguments given but expected 0. a.test({from: 0xf6a948bff792e4f42d7f17e5e4ebe20871d160f2});

Operating System: Windows 10
Truffle version: v3.4.11
Ethereum client: testrpc v4.1.3
node version: v8.7.0
npm version: 5.4.2

Best Answer

You cannot change the sender address from within solidity. The solidity tests are run inside the EVM and it doesn't allow the modification of the msg.sender. It is possible that a modified version of the EVM provides such functionality, but I'm not aware of such modification.

You can modify the function to test to accept an extra parameter, and pass there the sender you want

contract A {
    // We cannot test directly deposit
    function deposit(uint _amount) public {
        doDeposit(msg.sender, _amount);
    }
    // But we can test doDeposit
    function doDeposit(address _sender) public {
    }
}

contract TestA {
    address constant senderA = "0xA00...";
    address constant senderB = "0xB00...";
    function testDeposit() {
        A a = A(DeployedAddresses.A());
        a.doDeposit(senderA, 10000); 
        a.doDeposit(senderB, 10000); 
    }
}

It is not ideal, but it may help find some bugs.

Another option is to use the test contract address

contract TestA {
    address constant senderA = "0xA00...";
    address constant senderB = "0xB00...";
    function testMint() {
        // TestA is the owner a
        A a = new A(this);
        // Only the owner TestA can mint
        a.mint(senderA, 10000);
        // make senderA approve TestA
        a.doApprove(senderA, this, 1000);
        // testA can make a transfer from senderA
        a.transferFrom(senderA, senderB, 1000);
    }
}
Related Topic