关于第5课中,众筹合约fund函数的单元测试细节问题 #58
GodOfJiong
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
向deepseek提问如下:
我用solidity写了一个众筹的智能合约,其中有一个筹款函数,定义如下:
可以看出来,逻辑很简单,这里只需要关注一个点:那就是我有一个筹款的窗口期的判断,过了这个窗口期,就不能再调用这个函数进行筹款了,其它细节不用关注哈。
然后,我对这个函数用hardhat框架,配合使用mocha、chai这种单元测试工具,写了个单元测试用例,专门测试这个函数的窗口期有没有效果,代码如下:
这个地方,使用hardhat-network-helper插件,模拟了时间的流逝,让他触发窗口过期失效,然后调用crowdFund(也就是众筹合约)的fund函数(也就是筹款函数),外面包了个expect,意味着我就是预期它会调用失败,这个理论上确实是会通过的,而且运行了一下npx hardhat test之后,确实通过了测试。
但现在出现了一个细节问题,那就是我在expect里头调用的crowdFund.fund是没有在前面跟着await的,这样子反而测试通过了。但是我个人的理解,应该来说,这个函数调用的前头是要跟await的,因为他是个异步函数,也即写成:await crowdFund.fund,但是我按照这个理解去写的时候,运行单元测试反而失败了,报错如下:
test fund: window close:
Error: VM Exception while processing transaction: reverted with reason string 'can not fund out of the window'
at CrowdFund.fund (contracts/CrowdFund.sol:78)
at EdrProviderWrapper.request (node_modules\hardhat\src\internal\hardhat-network\provider\provider.ts:398:41)
at HardhatEthersSigner.sendTransaction (node_modules@nomicfoundation\hardhat-ethers\src\signers.ts:125:18)
at send (node_modules\ethers\src.ts\contract\contract.ts:313:20)
at Proxy.fund (node_modules\ethers\src.ts\contract\contract.ts:352:16)
at Context. (test\unit\testCrowdFund.js:40:13)
deepseek回答如下:
你遇到的问题涉及到 Hardhat 和 Ethers.js 的异步行为处理方式。让我们详细分析一下。
1. 为什么没有
await
时测试通过了?在 Hardhat 和 Ethers.js 中,当你调用一个可能会失败的交易(例如
fund
函数)时,Ethers.js 会返回一个 Promise。如果你不使用await
,这个 Promise 会立即返回,而不会等待交易的实际执行结果。在这种情况下,
expect
会捕获到 Promise 对象,并且chai
的.to.be.revertedWith
断言会等待这个 Promise 被拒绝(即交易失败),并且检查错误信息是否符合预期。因此,测试通过了。2. 为什么加上
await
后测试失败了?当你加上
await
时,代码会等待fund
函数的执行结果。如果fund
函数执行失败(即交易被 revert),Ethers.js 会抛出一个异常。这个异常会被expect
捕获,但由于你已经使用了await
,expect
实际上是在等待一个已经被 reject 的 Promise,因此测试失败。3. 如何正确编写测试?
为了正确测试这种情况,你应该使用
await
,并且将expect
包裹在一个try-catch
块中,或者使用chai
提供的.to.be.revertedWith
断言来处理异步异常。以下是正确的写法:
4. 解释
await expect(...)
:这里expect
会等待fund
函数的执行结果,并且捕获可能的异常。.to.be.revertedWith("can not fund out of the window")
:这个断言会检查交易是否被 revert,并且错误信息是否符合预期。5. 总结
await
时,expect
会捕获 Promise 并等待其被 reject,因此测试通过。await
时,expect
会捕获到已经被 reject 的 Promise,导致测试失败。await expect(...).to.be.revertedWith(...)
来正确处理异步异常。希望这个解释能帮助你理解问题并正确编写测试用例!
Beta Was this translation helpful? Give feedback.
All reactions