Solidity Testing – Contract Calling Another Contract with Different Addresses

addressessoliditytestingtestrpc

I have a wrapper contract that instantiates and calls another contract, and my test cases say the owners (msg.sender)s don't match. Why?

contract A

pragma solidity ^0.4.4;

contract A {

    function A() {
    }

    function createB(string name) {
        return new B(msg.sender, name);
    }
}

contract B

pragma solidity ^0.4.4;

contract B {
    address owner
    string public name;

    function B(address _owner, string _name) {
        owner = _owner;
        name = _name;
    }
}

test case

pragma solidity ^0.4.0;

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

contract TestB {
    B testB;
    A testA;

    function beforeEach() {
        A = A(DeployedAddresses.A());
        B = testA.createB("test");
    }

    function testOwnerIsSet() {
        Assert.equal(address(A), address(B), "Owner's address does not match");
    }
}

Test Results

 1) TestB testOwnerIsSet:
     Error: Owner's address does not match
      at /Users/xxx/.config/yarn/global/node_modules/truffle/build/cli.bundled.js:214233:17
      at Array.forEach (native)
      at processResult (/Users/xxx/.config/yarn/global/node_modules/truffle/build/cli.bundled.js:214231:19)
      at process._tickCallback (internal/process/next_tick.js:109:7)

EDIT

I have added the address public owner to contract A. And made owner public in contract B.

And now my TestB contract looks like this:

pragma solidity ^0.4.0;

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

contract TestB {
    B testB;
    A testA;

    function beforeEach() {
        A = A(DeployedAddresses.A());
        B = testA.createB("test");
    }

    function testOwnerIsSet() {
        address aOwner = A.owner();
        address bOwner = B.owner();
        Assert.equal(aOwner, bOwner, "Owner's address does not match");
    }
}

Best Answer

You should note that if you call createB like previously:

function createB(string name) public returns (address) {
  return new B(name)
}

Inside B constructor you will have msg.sender = address(A), because A is creating B.

To make it work as intended you have to send the owner to B constructor like this:

Contract A.sol
pragma solidity ^0.4.13;

import "./B.sol";

contract A {
    address public owner;
    function A() {
        owner = msg.sender;
    }

    function createB(string name) public returns (address) {
        return new B(owner, name);
    }
}
Contract B.sol
pragma solidity ^0.4.13;

contract B {
    address public owner;
    string public name;
    function B(address _owner, string _name) {
        owner = _owner;
        name = _name;
    }
}
Contract TestB.sol
pragma solidity ^0.4.13;

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/A.sol";
import "../contracts/B.sol";

contract TestB {
  B testB;
  A testA;

  function beforeEach() {
    testA = A(DeployedAddresses.A());
    testB = B(testA.createB("test"));
  }

  function testIsOwnerIsSet() {
    address aOwner = testA.owner();
    address bOwner = testB.owner();
    Assert.equal(aOwner, bOwner, "Owner's address does not match");
  }
}

Before Edit

But you never call owner you are comparing the addresses of contract A, and contract B. You should compare

Assert.equal(address(A), address(B.owner), "Owner's address does not match") 

But make sure owner is public in contract B.