Verträge mit Trüffel testen

Ich versuche, Tests für Verträge mit Trüffel zu schreiben; Ich habe hier ein Thema eröffnet . Der Arbeitsablauf ist wie folgt:

mkdir truffle_testing
truffle init
rm -r tests/* contracts/* build/*

Als nächstes erstelle ich die folgenden Vertragsdateien im Verzeichnis 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;
    }
}

und

Migrationen.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);
  }
}

Dann erstelle ich eine Testsuite im Verzeichnis tests/ :

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.");
       });
    });
  });
});

Nachdem alle Dateien geschrieben wurden starte ich testrpc :

testrpc:

EthereumJS TestRPC v2.1.0

Available Accounts
==================
...

Dann bauen Sie das Projekt:

truffle compile --compile-all
truffle migrate
truffle test

Wie erwartet werden alle Tests bestanden, aber sie werden auch bestanden, wenn ich den Wert im zweiten Test von 4 auf einen beliebigen anderen ganzzahligen Wert ändere.

Wieso den?

Bearbeiten:

Ich habe den fertigen Rückruf zu meinen Tests hinzugefügt, aber er funktioniert nicht (Tests werden immer noch als bestanden angezeigt, obwohl dies nicht der Fall sein sollte):

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); 
       });
    });
  });

});

Bearbeiten #2:

Ich habe versucht, den folgenden Code auszuführen:

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); 
       });
    });
  });

});

bekomme aber jetzt einen Timeout-Fehler:

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.

Antworten (1)

Ich denke, Ihr Problem hängt damit zusammen, wie Mocha mit asynchronem Code funktioniert : Sie müssen eine done() -Funktion an die it-Funktion übergeben und am Ende Ihres Tests ausführen, also wartet Mocha, bis es aufgerufen wird, um den Test durchzuführen. Sie haben Beispiele in der Testdatei metacoin.js, die mit Trüffel 1 geliefert wird (weiß nicht, wie v.2 geliefert wird).

In Ihrem Test sollten Sie also Folgendes tun:

it("Getting the words string from the contract", function(done) {
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\"");
})
.then(() => {done()})
.catch(done)
;
Ich habe versucht, den fertigen Rückruf zu verwenden, und die Tests bestehen immer noch (siehe die Änderungen in der Frage).
Kennen Sie ein Minimalbeispiel, das einen Zustandsänderungsaufruf für den Vertrag durchführt (seltsamerweise besteht der erste Test korrekt und schlägt fehl).
In Ihrer Bearbeitung haben Sie den Code nicht richtig eingefügt. done ist eine Funktion, die der Methode it() als Parameter übergeben werden muss. Dann muss es in einem .then() aufgerufen werden. Sie müssen done als Parameter übergeben, um mocha zu zwingen, auf die Ausführung von done() zu warten, um den Test durchzuführen. Wenn nicht, werden Ihre it()-Funktionen einfach als leer behandelt, da der darin enthaltene Code asynchron ist. Später füge ich ein Beispiel für Mokka-Tests ein, die Vertragsstatusänderungen durchführen.
OK danke. Ich habe den Vorschlag ausprobiert und einen Timeout-Fehler erhalten (ich habe die Frage in der zweiten Bearbeitung aktualisiert).
Mmm, ich denke, Sie sollten Ihren Code nicht mit then(/*code*/).done()... beenden, sondern mit then(/*code mit dem Aufruf*/).then(/*Code, der den Test durchführt* /).then(done).catch(done).
Ich lade ein Beispiel hoch, an dem ich gearbeitet habe: github.com/Sergeon/ethereum-truffle-solidity-ballot-contract Wie auch immer, Truffle v.1, ich hoffe, es hilft.