[Ethereum] Mock Smart Contract For Unit Testing

contract-designsoliditystoragetruffleunittesting

I'm new to Ethereum and solidity, I'm developing a simple decentralized application using Truffle where I have an abstract contract Storage and another contract Reader which uses storage.

contract Storage {
    function getWeight() public view returns(uint8);
    function setWeight(uint8 weight) public view returns(bool); 
}

contract Reader {
    Storage private storage;
    constructor(address storageAddress) {
        storage = Storage(storageAddress);
    }
}

I'm trying to write unit test for contract Reader, is there anyway to mock the behavior of the abstract contract? If not, then what is the best practices for that situation?

Best Answer

I created a little implementation of the Storage contract. Note that I renamed your abstraction to StorageInterface.

I also added some functions to Reader, since there isn't much to test unless it does something. So, now you have a setter/getter in the Reader that forwards to a Storage contract which is an implementation of the interface.

On looking at it, I decided I was uncomfortable with using "Storage" because this is a reserved word in the lower case form. I also dispensed with the uint8 that looks like premature optimization.

One other little thing. The Interface declared the setter as view, but it can't be since it writes to the contract state.

pragma solidity 0.4.24;

contract StoreInterface {
    function getWeight() public view returns(uint);
    function setWeight(uint weight) public returns(bool); 
}

/**
 * Just a very simple set of stubs ...
 * Deploy a "Store" and then pass its address into Reader's constructor.
 */

contract Store is StoreInterface {

    uint weight;

    event LogSetWeight(address sender, uint weight);

    function getWeight() public view returns(uint) {
        return weight;
    }

    function setWeight(uint _weight) public returns(bool) {
        weight = _weight;
        emit LogSetWeight(msg.sender, _weight);
        return true;
    } 
}

contract Reader {

    StoreInterface store;

    constructor(address storeAddress) public {
        store = StoreInterface(storeAddress);
    }

    function getWeight() public view returns(uint) {
        return store.getWeight();
    }

    function setWeight(uint weight) public returns(bool) {
        return store.setWeight(weight);
    }
}

Hope it helps.

Related Topic