I'm trying to write tests for contracts using truffle; I have opened an issue here. The workflow is as follows:
mkdir truffle_testing
truffle init
rm -r tests/* contracts/* build/*
Next, I create the following contract files in directory contracts/ :
C.sol
contract C {
string words = "Bla bla bla";
uint256 lastVal;
function math(uint256 a, uint256 b) {
lastVal = a + b;
}
function getVal() constant returns (uint256) {
return lastVal;
}
function getWords() constant returns (string) {
return words;
}
}
and
Migrations.sol
contract Migrations {
address public owner;
// A function with the signature `last_completed_migration()`, returning a uint, is required.
uint public last_completed_migration;
modifier restricted() {
if (msg.sender == owner) _
}
function Migrations() {
owner = msg.sender;
}
// A function with the signature `setCompleted(uint)` is required.
function setCompleted(uint completed) restricted {
last_completed_migration = completed;
}
function upgrade(address new_address) restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}
Then I create a test suite in the tests/ directory:
contract('C', function(accounts) {
it("Getting the words string from the contract", function() {
var c = C.deployed();
return c.getWords.call(accounts[0]).then(function(words) {
assert.equal(words, "Bla bla bla", "[E] The contract should have said \"Bla bla bla\"");
});
});
it(" 2 + 2 = 4 ", function(){
var c = C.deployed();
// Call method to initialize value (this method only returns the tx id and not the
// actual value)
c.math(2, 2, {from:accounts[0],gas:3000000}).then(function(tx_that_we_dont_need) {
return c.getVal.call().then(function(additionResult){
assert.equal(additionResult, 4, "[E] 2 + 2 = 4 even in eth. contracts.");
});
});
});
});
After all files have been written I launch testrpc:
testrpc:
EthereumJS TestRPC v2.1.0
Available Accounts
==================
...
then build the project:
truffle compile --compile-all
truffle migrate
truffle test
As expected, all tests pass but they also pass if I change the value in the second test from 4 to any other integer value.
Why?
Edit:
I've added the done callback to my tests but it doesn't work (tests still show up as passing when they shouldn't):
contract('C', function(accounts) {
it("Getting the words string from the contract", function() {
var c = C.deployed();
return c.getWords.call(accounts[0]).then(function(words) {
assert.equal(words, "Bla bla bla", "[E] The contract should have said \"Bla bla bla\"");
});
});
it(" 2 + 2 = 4 ", function(){
var c = C.deployed();
// Call method to initialize value (this method only returns the tx id and not the
// actual value)
c.math(2, 2, {from:accounts[0],gas:3000000}).then(function() {
return c.getVal.call().then(function(additionResult){
assert.equal(additionResult, 6, "[E] 2 + 2 = 4 even in eth. contracts.");
done();
}).done(null, function(error) {
done(error);
});
});
});
});
Edit #2:
I have tried running the following code:
contract('C', function(accounts) {
it("Getting the words string from the contract", function() {
var c = C.deployed();
return c.getWords.call(accounts[0]).then(function(words) {
assert.equal(words, "Bla bla bla", "[E] The contract should have said \"Bla bla bla\"");
});
});
it(" 2 + 2 = 4 ", function(){
var c = C.deployed();
// Call method to initialize value (this method only returns the tx id and not the
// actual value)
c.math(2, 2, {from:accounts[0],gas:3000000}).then(function() {
return c.getVal.call().then(function(additionResult){
assert.equal(additionResult, 6, "[E] 2 + 2 = 4 even in eth. contracts.");
done();
}).done(null, function(error) {
done(error);
});
});
});
});
but now get a timeout error:
Contract: C
✓ Getting the words string from the contract (232ms)
1) 2 + 2 = 4
> No events were emitted
1 passing (5m)
1 failing
1) Contract: C 2 + 2 = 4 :
Error: timeout of 300000ms exceeded. Ensure the done() callback is being called in this test.