Testrpc

預期會引發錯誤的松露測試承諾

  • January 2, 2019

我與檢查輸入參數的方法簽訂了契約,require(bool)因此如果至少有一個條件不匹配,則會引發錯誤。在測試過程中(使用 Truffle 和 Chaijs),它看起來像:

Error: VM Exception while processing transaction: invalid opcode
 at Object.InvalidResponse (/usr/lib/node_modules/truffle/build/cli.bundled.js:37022:16)
 at /usr/lib/node_modules/truffle/build/cli.bundled.js:210096:36
 at XMLHttpRequest.request.onreadystatechange (/usr/lib/node_modules/truffle/build/cli.bundled.js:208875:13)
 at XMLHttpRequestEventTarget.dispatchEvent (/usr/lib/node_modules/truffle/build/cli.bundled.js:210748:18)
 at XMLHttpRequest._setReadyState (/usr/lib/node_modules/truffle/build/cli.bundled.js:211038:12)
 at XMLHttpRequest._onHttpResponseEnd (/usr/lib/node_modules/truffle/build/cli.bundled.js:211193:12)
 at IncomingMessage.<anonymous> (/usr/lib/node_modules/truffle/build/cli.bundled.js:211153:24)
 at endReadableNT (_stream_readable.js:1047:12)
 at _combinedTickCallback (internal/process/next_tick.js:102:11)
 at process._tickCallback (internal/process/next_tick.js:161:9)

測試使用這樣的承諾:

return MyToken.deployed().then(inst => {
 instance = inst;
 return instance.purchase({from: accounts[1], value: amount});
})....

問題是我無法處理這個異常。我試圖將purchase呼叫包裝到函式中並使用assert.throws(executor, message)- 它不起作用(假設由於它需要同步的東西)。

如何測試這個承諾(最好不添加chai-as-promised)?

~~在進一步處理之前,您可以catch在被拒絕時做出承諾。~~Catch 在範例中不起作用,因為它不僅會擷取事務失敗,還會擷取任何其他錯誤。

您可以使用第二個參數來then擷取在進一步處理之前被拒絕的承諾,即MyPromise.then(() => { /* check when succeed */ }, () => { /* check when failure */ })

contract('MyToken', (accounts) => {
 it("Should fail", () => {
   return MyToken.deployed().then((instance) => {
     return instance.purchase({ from: accounts[1], value: amount });
   }).then(() => {
     assert.ok(false, "It didn't fail");
   }, () => {
     assert.ok(true, "Passed");
   });
 });
});

Promise 不會拋出,這就是assert.throws失敗的原因。

Byzantium 之後的注意事項:另外我應該提到,在 Byzantium 分叉之後,以前生成 throw 的一些操作將不再做這樣的事情。檢查這篇文章,以便您可以針對該事實更新您的測試:由於 REVERT 操作碼不消耗所有氣體,如何在拜占庭分叉後檢測失敗的交易?


也許更好的方法是使用 async/await 和assert.throws.

訣竅是將承諾轉換為assert.throws可以報告的非非同步內容。第一個輔助函式

async function verifyThrows(pred, message) {
 let e;
 try {
   await pred();
 } catch (ex) {
   e = ex;
 }
 assert.throws(() => {
   if (e) { throw e; }
 }, message);
}

我們可以使用輔助函式在函式中傳遞承諾執行

contract('MyToken', (accounts) => {
 it("Should fail", async () => {
   const instance = await MyToken.deployed();
   await verifyThrows(() => {
     instance.purchase({ from: accounts[1], value: amount });
   }, /revert/);
 })
});

引用自:https://ethereum.stackexchange.com/questions/27846