Truffle: Unit tests written in Solidity, how to change msg.sender address, msg.value,...

Created on 30 Oct 2017  路  12Comments  路  Source: trufflesuite/truffle

  • [ x] I've asked for help in the Truffle Gitter before filing this issue.

Issue

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.

Steps to Reproduce

`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?
}
}`

Expected Behavior

In gitter I got a response so I have tried to run it like this:
a.test({from: 0xf6a948bff792e4f42d7f17e5e4ebe20871d160f2});

Actual Results

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

Environment

  • 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

Most helpful comment

@berar - You can always take the hard way, by having a "testMethod" that instantiates a contract, that will then call your specified method, that way the msg.sender is the "new instance", thus allowing you to test for cases where the "code needs to revert / throw" in case of a different sender.

Just remember you will most likely need to use the low level "call" and check for true / false on the execution.
Problem with call is that you can only use it to determine if execution was successful or not. And in order to retrieve the method's return value you're going to have to go into assembly and do some memory assignment yourself.

It's nice to think of "solidity tests" as unit tests, and JS ones as integration, but in reality you probably want to stick to JS, as that's what everyone seems to be using these days.

All 12 comments

You can't change msg.sender in Solidity. Its value will always be the address making the call.
a.test({from: 0xf6a948bff792e4f42d7f17e5e4ebe20871d160f2}); is JavaScript code, not Solidity.

Is it possible to implement this? Along with the possibility of a change of msg.value and the likes? To be frank, I am surprised that this isn't possible currently since it should play a major part of the test cases given the scope.

It's already possible with Javascript tests, which is what most people use.
Read more here: http://truffleframework.com/docs/getting_started/javascript-tests

I know, except that I am getting eth_call: invalid opcode error when I am calling functions with parameters. Still, given that there is a possibility of writing tests in solidity, a way to access 'from' field should exist.

@berar - You can always take the hard way, by having a "testMethod" that instantiates a contract, that will then call your specified method, that way the msg.sender is the "new instance", thus allowing you to test for cases where the "code needs to revert / throw" in case of a different sender.

Just remember you will most likely need to use the low level "call" and check for true / false on the execution.
Problem with call is that you can only use it to determine if execution was successful or not. And in order to retrieve the method's return value you're going to have to go into assembly and do some memory assignment yourself.

It's nice to think of "solidity tests" as unit tests, and JS ones as integration, but in reality you probably want to stick to JS, as that's what everyone seems to be using these days.

Hi all,

@micky has the correct answer here - if you want to change your msg.sender in solidity tests, you need to make your test contract (TestSomething.sol) the owner of contract under test.

invalid opcode and revert are separate issues; what they mean is that your Solidity code had a runtime error when executing your transaction. _Why_ it had a runtime error depends on your code.

I'd recommend using the Truffle debugger any time you run into this error.

I'm going to close this ticket as @micky's answer is correct. Cheers!

@tcoulter but what if i want to test if my contract is properly storing/responding to multiple addresses?

E.g. if I have a Contract attribute of type array or some mapping with key being the sender address, i want to make sure the array is properly storing multiple users data.

I can only interact with my solidity test contract under 1 address?

I think I found an example how to do it in JS, which seems to be more capable: https://github.com/gustavoguimaraes/smart-contract-testing-javascript-example-/blob/master/test/fundRaise.js

UPDATE: Since 1.5 years I only use JS for testing Solidity contracts.

@EnchanterIO Did you find something in solidity to do it? Having hard time to switch b/w accounts in testrpc . How can i interact with my solidity test contract with more then 1 address?

Bug was probably introduced in 5.0.31. 5.0.30 works for me on Linux.

@digulla this issue is not a bug, it's the way msg.sender works in solidity, you probably have the wrong thread.

For those looking for a way to manipulate msg.sender in unit tests written in solidity, here's an alternative approach I've been using effectively:

  1. Create "actor" contracts, i.e., contracts that implement a unit test actor behavior and that make calls to the contract under test (CUT)
  2. Deploy one actor contract for each individual address you need for writing your unit tests. For instance, if you're writing test cases for an ERC20 contract you can implement a SenderContract and a ReceiverContract, each one will have its own address and when they call the CUT functions msg.sender will be set to their deployed addresses
  3. Now when writing unit tests instead of calling the CUT functions directly compose the test case as a sequence of actor function calls
Was this page helpful?
0 / 5 - 0 ratings