Solidity
Truffle 最佳實踐 - 單元與集成測試
考慮有兩個契約:
- 模擬令牌
- Faucet(將令牌地址作為建構子參數)
要進行單元測試
Faucet
,我將創建兩個新實例:const token = await MockToken.new() const faucet = await Faucet.new(token.address)
現在我可以單獨執行所有測試,以確保
Faucet
按預期工作,但我如何確保部署Faucet
的令牌引用正確的令牌地址並且我沒有在遷移中錯誤地提供錯誤的地址?我是否只是得到
Faucet.deployed()
並檢查他的令牌地址是否是我所期望的?如果是這樣,我應該在包含單元測試的同一個文件中還是在單獨的文件中執行它?
可能有更好的方法來做到這一點,但通常,我預先計算預期的已部署合約地址,然後執行檢查以驗證已部署的合約地址是否與預期地址匹配,如果任何不匹配,我中止遷移:
const ethers = require('ethers'); const utils = require('../lib/utils/utils.js'); const Governance = artifacts.require("Governance"); const privateKey = process.env["PRIVATE_KEY"]; module.exports = function(deployer, network, accounts) { deployer.then(async () => { let provider = ethers.getDefaultProvider("rinkeby"); let walletWithProvider = new ethers.Wallet(privateKey, provider); let walletPublicKey = walletWithProvider.address; const nonce = await walletWithProvider.getTransactionCount(); console.log('\r\nCurrent nonce: ', nonce); const GovernanceAddress = await utils.getAddress(walletPublicKey, nonce + 1); console.log(`\r\nExpected GovernanceAddress: ${GovernanceAddress}`); const GovernanceContract = await deployer.deploy(Governance); if(GovernanceContract.address.toLowerCase() !== GovernanceAddress) { throw new Error("GovernanceContract Address Does Not Match Expected Address (GovernanceAddress) - Aborting Deployment"); } }); }
這是用於
utils.getAddress
預先計算合約地址的 utils 函式:import { solidityKeccak256 } from 'ethers/utils'; import * as rlp from 'rlp'; export const getAddress = (deployer, nonce) => { return ( '0x' + solidityKeccak256(['bytes'], [rlp.encode([deployer, nonce])]) .slice(12) .substring(14) ); };
希望對您的情況有所幫助:)
當您希望兩個契約密切相關時,我會在執行測試之前創建兩個契約
contract('MyContract', async () => { let token let faucet // This function will execute once before all the tests before(async () => { token = await MockToken.new() faucet = await Faucet.new(token.address) }) it('Faucet', async () => { assert(....) }) })