使用Waffle+Chai测试ERC721智能合约时回滚断言失效问题
解决Chai回滚断言未生效的问题
我一眼就看出问题出在哪了——你在expect()里面多写了await,这直接导致Chai的回滚断言根本没机会生效!
核心原因:错误地提前执行了交易/调用
Chai Waffle的.to.be.reverted和.to.be.revertedWith()断言,需要接收一个未被执行的Promise(也就是还没加await的合约调用/交易)。如果在expect()内部加了await,会直接触发合约调用,一旦合约revert,这个异常会直接抛出来,测试框架会立刻判定测试失败,而不是让断言去验证这个预期的回滚。
修正你的测试代码
1. 非Owner调用失败的测试用例
把expect内部的await去掉:
it('should fail when non-owner calls the function', async () => { let addGenesisHoldersTx = await myToken.addGenesisTokenHolderAddresses(genesisTokenHolders) await addGenesisHoldersTx.wait(); // 移除expect括号里的await,让断言处理交易执行 await expect(myToken.connect(addr1).airdropTokensToGenesisHolders(1, 2)).to.be.revertedWith("Ownable: caller is not the owner"); })
2. Owner调用成功的测试用例
同样要去掉验证不存在Token时的await:
it('should succeed when called by the owner', async () => { let addGenesisHoldersTx = await myToken.addGenesisTokenHolderAddresses(genesisTokenHolders) await addGenesisHoldersTx.wait(); let airdropTx = await myToken.connect(deployer).airdropTokensToGenesisHolders(1,2); await airdropTx.wait(); // 正常调用的ownerOf需要await获取结果,这部分没问题 await expect(await myToken.ownerOf(1)).to.hexEqual(addr1.address) await expect(await myToken.ownerOf(2)).to.hexEqual(addr2.address) // 这里移除await,让断言捕获预期的revert await expect(myToken.ownerOf(1000)).to.be.reverted; })
额外说明
- 对于预期正常执行的合约调用(比如
ownerOf(1)),需要用await获取结果后再做断言; - 对于预期会revert的调用,必须把未执行的Promise传给
expect,让Chai的断言逻辑去处理交易执行和异常捕获。
这样修改后,你的测试就能按照预期通过——断言会正确捕获revert,并验证错误信息是否符合预期,而不是直接抛出异常导致测试失败。
内容的提问来源于stack exchange,提问作者Craigson
相关产品推荐
相关产品推荐

