Truffle
如何在 truffle 測試 javascript 中擷取“還原”錯誤?
如何在用 javascript 編寫的松露測試中擷取“還原”錯誤?
Error: VM Exception while processing transaction: revert
這是測試契約的一部分,
function doRevert() public { revert(); }
這是我測試javascript的一部分,
it("test1.....", async() => { let instant = await myContract.deployed(); await instant.doRevert(); . . .
我不想在第一個測試步驟中停止我的測試程式碼。我搜尋了我可以導入
expectThrow.js
,但我無法導入它,與此處相同的問題。我知道這個問題與How can you handle an expected throw in a contract test using truffle and ethereum-testRPC 非常相關?,但仍然無法弄清楚如何使用庫,expectThrow.js
並且不推薦使用 throw ,所以還有其他方法可以做到這一點嗎?
舉例回答:
假設您有一個只能由合約的所有者(部署者)呼叫的函式。
如果它被所有者以外的任何人呼叫,那麼它會恢復(
require
帶有false
條件)。文件
exceptions.js
:module.exports.errTypes = { revert : "revert", outOfGas : "out of gas", invalidJump : "invalid JUMP", invalidOpcode : "invalid opcode", stackOverflow : "stack overflow", stackUnderflow : "stack underflow", staticStateChange : "static state change" } module.exports.tryCatch = async function(promise, errType) { try { await promise; throw null; } catch (error) { assert(error, "Expected an error but did not get one"); assert(error.message.startsWith(PREFIX + errType), "Expected an error starting with '" + PREFIX + errType + "' but got '" + error.message + "' instead"); } }; const PREFIX = "VM Exception while processing transaction: ";
文件
MyContractTest.js
:contract("MyContractTest", function(accounts) { let myContract; let owner = accounts[0]; let nonOwner = accounts[1]; let tryCatch = require("./exceptions.js").tryCatch; let errTypes = require("./exceptions.js").errTypes; describe("sanity assertion:", function() { before(async function() { myContract = await artifacts.require("MyContract.sol").new(); }); it("should complete successfully", async function() { await myContract.func({from: owner}); }); it("should abort with an error", async function() { await tryCatch(myContract.func({from: nonOwner}), errTypes.revert); }); }); });
更新:版本 2
我想用稍微簡單的程式碼來更新這個答案。它的行為應該是相同的,但它在測試本身中“節省了一些字元”,從而提高了可讀性並允許更容易維護。
文件
exceptions.js
:const PREFIX = "Returned error: VM Exception while processing transaction: "; async function tryCatch(promise, message) { try { await promise; throw null; } catch (error) { assert(error, "Expected an error but did not get one"); assert(error.message.startsWith(PREFIX + message), "Expected an error starting with '" + PREFIX + message + "' but got '" + error.message + "' instead"); } }; module.exports = { catchRevert : async function(promise) {await tryCatch(promise, "revert" );}, catchOutOfGas : async function(promise) {await tryCatch(promise, "out of gas" );}, catchInvalidJump : async function(promise) {await tryCatch(promise, "invalid JUMP" );}, catchInvalidOpcode : async function(promise) {await tryCatch(promise, "invalid opcode" );}, catchStackOverflow : async function(promise) {await tryCatch(promise, "stack overflow" );}, catchStackUnderflow : async function(promise) {await tryCatch(promise, "stack underflow" );}, catchStaticStateChange : async function(promise) {await tryCatch(promise, "static state change");}, };
文件
MyContractTest.js
:contract("MyContractTest", function(accounts) { let myContract; let owner = accounts[0]; let nonOwner = accounts[1]; let catchRevert = require("./exceptions.js").catchRevert; describe("sanity assertion:", function() { before(async function() { myContract = await artifacts.require("MyContract.sol").new(); }); it("should complete successfully", async function() { await myContract.func({from: owner}); }); it("should abort with an error", async function() { await catchRevert(myContract.func({from: nonOwner})); }); }); });