You need to add the constant
keyword to the test()
function like:
pragma solidity ^0.4.0;
contract Test {
mapping (address => uint256) weismap;
function bet(uint vote) payable returns (uint256 weis) {
if (msg.value==0)
throw;
weismap[msg.sender]= msg.value;
return weismap[msg.sender];
}
function test() constant returns (uint myVote) {
return 1;
}
}
Calling bet(...)
with the value 2. Note that I'm sending 2 ethers as well with the transaction:
Now I call test()
AND I've left the value 2. This call to test()
fails as the constant function is being called as a transaction, not a read of the values off the blockchain:
If I call test()
AND I've set value to blank, this call to test()
succeeds as the constant function is being called as a read of the values off the blockchain:
You can catch
a promise when it was rejected before further processing. Catch doesn'y work in the example because it will catch any other error not only the transaction failure.
You can use the second parameter to then
to catch a promise being rejected before further processing, ie 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");
});
});
});
Promises do not throws that is why assert.throws
fails.
Note after Byzantium: Also I should mention that after the Byzantium fork some operations that previously generated a throw will no longer do such thing. Check this post so you can update your test for that fact: How do I detect a failed transaction after the Byzantium fork as the REVERT opcode does not consume all gas?
Perhaps a better approach is using async/await, and assert.throws
.
The trick is convert the promise to something not async that assert.throws
can report. Firs a helper function
async function verifyThrows(pred, message) {
let e;
try {
await pred();
} catch (ex) {
e = ex;
}
assert.throws(() => {
if (e) { throw e; }
}, message);
}
And we can use the helper function passing the promise execution in a function
contract('MyToken', (accounts) => {
it("Should fail", async () => {
const instance = await MyToken.deployed();
await verifyThrows(() => {
instance.purchase({ from: accounts[1], value: amount });
}, /revert/);
})
});
Best Answer
You can use OpenZeppelin's expectThrow helper -
Source: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/test/helpers/expectThrow.js
I use it my test cases like this -