如何在编写时测试带输出的 Solidity 代码?

How to test Solidity code w/ output as you are writing it?

我知道这是一个非常初学者的问题,所以请多多包涵。我最近开始了我在 Solidity 中的第一个项目,完全来自 Python。在使用 Python 时,我不断地注入打印语句来检查我的工作输出并确保一切都按计划进行。

我很难用 Solidity 复制相同的工作流程。即使在 IDE 前面,我也使用 PyCharm 和 Python,它有一个 运行 命令和输出 window,但我找不到任何可比的 Solidity。我正在使用 Sublime Text,但这似乎只适合编写实际代码,但我找不到将 functions/mappings 等调用到 window 以检查输出的方法。

Remix 的功能比大多数都多,但我更喜欢本地开发环境。我已经找了一段时间了,感觉自己找错了地方,不确定为什么对于看似简单的问题很难找到答案。任何见解都将是惊人的。

谢谢!

Solidity 没有命令行输出来显示调试值。这可以说服您编写遵循 single-responsibility 原则的更简单的函数并分别测试它们的 input/output。

所以与其写一个长函数来做所有事情并且很难知道执行过程中发生了什么

function transfer(uint256 _tokenId) external {
    require(msg.sender == ownerOf(_tokenId)
        || isApprovedForAll(ownerOf(_tokenId), msg.sender)
        || msg.sender == getApproved(_tokenId), 'Sender not allowed');

    if (approved != address(0x0)) {
        tokenApprovals[_tokenId] = address(0x0);
        emit Approval(_tokenOwner, address(0x0), _tokenId);
    }

    // ... etc
}

您可以将功能分解成更小的部分(更容易单独测试)。如果需要,您可以将它们连接到一个函数中。

function transfer(uint256 _tokenId) {
    address tokenOwner = ownerOf(_tokenId);
    address approved = getApproved(_tokenId);

    require(isSenderAllowed(_tokenId, tokenOwner, approved), 'Sender not allowed');

    if (approved != address(0x0)) {
        _removeApproval(_tokenId, tokenOwner);
    }

    // ... etc
}
function isSenderAllowed(uint256 _tokenId, address _tokenOwner, address _approved) external view returns (bool) {
    return (msg.sender == _tokenOwner
        || isApprovedForAll(_tokenOwner, msg.sender)
        || msg.sender == _approved);
}
function _removeApproval(uint256 _tokenId, address _tokenOwner) private {
    tokenApprovals[_tokenId] = address(0x0);
    emit Approval(_tokenOwner, address(0x0), _tokenId);
}

调试的一个小解决方法(在本地区块链上,例如 Ganache 或 Remix VM 模拟器)可以使用事件日志。您可以在交易 return 对象中看到它们(如果交易未被还原)。然而,这不是一个好的做法,我仍然建议您编写尽可能简单的函数,这样您就不必进行那么多调试。

contract MyContract {
    event LogString(string memory _value);
    event LogAddress(address _value);

    function foo() external {
        emit LogString("myString");
        emit LogAddress(address(0x123));
    }
}