a.t*_*.t. 10 random unit-testing solidity chainlink
在尝试建立一个基本的自托管单元测试环境(和 CI)来测试这个 Chainlink VRF 随机数合约时时,我在如何在本地模拟任何相关的区块链/测试网方面遇到了一些困难。
\n例如,我发现这个测试 Chainlinks VRF 的存储库。但是,对于默认部署,它建议/需要免费,KOVAN_RPC_URL例如来自 Infura 的站点,甚至对于“本地部署”,它建议/需要免费MAINNET_RPC_URL例如来自 Alchemy 的站点。
我采用了waffle框架的单元测试环境,描述如下:
\nsrc____AmIRichAlready.sol\n |____RandomNumberConsumer.sol\n |\ntest____AmIRichAlready.test.ts\n |____mocha.opts\npackage.json\ntsconfig.json\nwaffle.json\nyarn.lock\nRun Code Online (Sandbox Code Playgroud)\nAmIRichAlready.sol
\npragma solidity ^0.6.2;\n\ninterface IERC20 {\n function balanceOf(address account) external view returns (uint256);\n}\n\ncontract AmIRichAlready {\n IERC20 private tokenContract;\n uint public richness = 1000000 * 10 ** 18;\n\n constructor (IERC20 _tokenContract) public {\n tokenContract = _tokenContract;\n }\n\n function check() public view returns (bool) {\n uint balance = tokenContract.balanceOf(msg.sender);\n return balance > richness;\n }\n\n // IS THIS NEEDED???\n function setRichness(uint256 _richness) public {\n richness = _richness;\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n文件内容RandomNumberConsumer.sol已经在 stackexange 上了。
AmIRichAlready.test.ts
\nimport {expect, use} from \'chai\';\nimport {Contract, utils, Wallet} from \'ethers\';\nimport {deployContract, deployMockContract, MockProvider, solidity} from \'ethereum-waffle\';\n\nimport IERC20 from \'../build/IERC20.json\';\nimport AmIRichAlready from \'../build/AmIRichAlready.json\';\n\nuse(solidity);\n\ndescribe(\'Am I Rich Already\', () => {\n let mockERC20: Contract;\n let contract: Contract;\n let vrfContract: Contract;\n let wallet: Wallet;\n\n beforeEach(async () => {\n [wallet] = new MockProvider().getWallets();\n mockERC20 = await deployMockContract(wallet, IERC20.abi);\n contract = await deployContract(wallet, AmIRichAlready, [mockERC20.address]);\n vrfContract = await deployContract(wallet, RandomNumberConsumer);\n });\n\n it(\'checks if contract called balanceOf with certain wallet on the ERC20 token\', async () => {\n await mockERC20.mock.balanceOf\n .withArgs(wallet.address)\n .returns(utils.parseEther(\'999999\'));\n await contract.check();\n expect(\'balanceOf\').to.be.calledOnContractWith(mockERC20, [wallet.address]);\n });\n\n it(\'returns false if the wallet has less than 1000000 coins\', async () => {\n await mockERC20.mock.balanceOf\n .withArgs(wallet.address)\n .returns(utils.parseEther(\'999999\'));\n expect(await contract.check()).to.be.equal(false);\n });\n\n it(\'returns true if the wallet has at least 1000000 coins\', async () => {\n await mockERC20.mock.balanceOf\n .withArgs(wallet.address)\n .returns(utils.parseEther(\'1000000\'));\n expect(await contract.check()).to.be.equal(false);\n });\n});\nRun Code Online (Sandbox Code Playgroud)\n摩卡选项
\n-r ts-node/register/transpile-only\n--timeout 50000\n--no-warnings\ntest/**/*.test.{js,ts}\nRun Code Online (Sandbox Code Playgroud)\n包.json
\n{\n "name": "example-dynamic-mocking-and-testing-calls",\n "version": "1.0.0",\n "main": "index.js",\n "license": "MIT",\n "scripts": {\n "test": "export NODE_ENV=test && mocha",\n "build": "waffle",\n "lint": "eslint \'{src,test}/**/*.ts\'",\n "lint:fix": "eslint --fix \'{src,test}/**/*.ts\'"\n },\n "devDependencies": {\n "@openzeppelin/contracts": "^4.3.1",\n "@types/chai": "^4.2.3",\n "@types/mocha": "^5.2.7",\n "@typescript-eslint/eslint-plugin": "^2.30.0",\n "@typescript-eslint/parser": "^2.30.0",\n "chai": "^4.3.4",\n "eslint": "^6.8.0",\n "eslint-plugin-import": "^2.20.2",\n "ethereum-waffle": "^3.4.0",\n "ethers": "^5.0.17",\n "mocha": "^7.2.0",\n "ts-node": "^8.9.1",\n "typescript": "^3.8.3"\n }\n}\nRun Code Online (Sandbox Code Playgroud)\ntsconfig.json
\n{\n "compilerOptions": {\n "declaration": true,\n "esModuleInterop": true,\n "lib": [\n "ES2018"\n ],\n "module": "CommonJS",\n "moduleResolution": "node",\n "outDir": "dist",\n "resolveJsonModule": true,\n "skipLibCheck": true,\n "strict": true,\n "target": "ES2018"\n }\n\n // custom test in vrfContract\n it(\'Tests if a random number is returned\', async () => {\n expect(await vrfContract.getRandomNumber()).to.be.equal(7);\n });\n}\nRun Code Online (Sandbox Code Playgroud)\n华夫饼.json
\n{\n "compilerType": "solcjs",\n "compilerVersion": "0.6.2",\n "sourceDirectory": "./src",\n "outputDirectory": "./build"\n}\nRun Code Online (Sandbox Code Playgroud)\n文件yarn.lock内容有点大,而且是自动生成的,所以你可以在 Waffle 框架存储库上找到它。同样,可以在这里package.json找到可以在同一存储库中
还可以在此处简单地克隆具有指定文件结构的存储库并使用以下命令运行测试:
\ngit clone git@github.com:a-t-2/chainlink.git\ngit clone git@github.com:a-t-2/test_vrf3.git\ncd test_vrf3\nsudo apt install npm\nnpm install\nnpm audit fix\nnpm install --save-dev ethereum-waffle\nnpm install @openzeppelin/contracts -D\nnpm i chai -D\nnpm i mocha -D\nrm -r build\nnpx waffle\nnpx mocha\nnpm test\nRun Code Online (Sandbox Code Playgroud)\n这将测试AmIRichAlready.sol文件并输出:
Am I Rich Already\n \xe2\x9c\x93 checks if contract called balanceOf with certain wallet on the ERC20 token (249ms)\n \xe2\x9c\x93 returns false if the wallet has less than 1000000 coins (190ms)\n \xe2\x9c\x93 returns true if the wallet has at least 1000000 coins (159ms)\n Tests if a random number is returned:\n Error: cannot estimate gas; transaction may fail or may require manual gas limit (error={"name":"RuntimeError","results":{"0x0a0b028de6cf6e8446853a300061305501136cefa5f5eb3e96afd95dbd73dd92":{"error":"revert","program_counter":609,"return":"0x"}},"hashes":["0x0a0b028de6cf6e8446853a300061305501136cefa5f5eb3e96afd95dbd73dd92"],"message":"VM Exception while processing transaction: revert"}, tx={"data":"0xdbdff2c1","to":{},"from":"0x17ec8597ff92C3F44523bDc65BF0f1bE632917ff","gasPrice":{"type":"BigNumber","hex":"0x77359400"},"type":0,"nonce":{},"gasLimit":{},"chainId":{}}, code=UNPREDICTABLE_GAS_LIMIT, version=abstract-signer/5.4.1)\n at Logger.makeError (node_modules/@ethersproject/logger/src.ts/index.ts:225:28)\n at Logger.throwError (node_modules/@ethersproject/logger/src.ts/index.ts:237:20)\n at /home/name/git/trucol/tested/new_test/test_vrf3/node_modules/@ethersproject/abstract-signer/src.ts/index.ts:301:31\n at process._tickCallback (internal/process/next_tick.js:68:7)\n\n\n\n 3 passing (4s)\nRun Code Online (Sandbox Code Playgroud)\n我需要哪组文件、文件结构和命令来自动测试是否getRandomNumber()返回整数,否则返回错误?
gli*_*a93 10
我也遇到了这个问题,通过mock解决了。这是我的 MockVRFCoordinator:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
contract MockVRFCoordinator {
uint256 internal counter = 0;
function requestRandomWords(
bytes32,
uint64,
uint16,
uint32,
uint32
) external returns (uint256 requestId) {
VRFConsumerBaseV2 consumer = VRFConsumerBaseV2(msg.sender);
uint256[] memory randomWords = new uint256[](1);
randomWords[0] = counter;
consumer.rawFulfillRandomWords(requestId, randomWords);
counter += 1;
}
}
Run Code Online (Sandbox Code Playgroud)
您可以在我的存储库中查看测试示例
| 归档时间: |
|
| 查看次数: |
2939 次 |
| 最近记录: |