Wie man Modifikatoren in Solidity testet

Ich verwende das https://github.com/dapphub/dapp-Framework zum Schreiben von Solidity-Verträgen und deren ds-test- Unit-Test-Framework.

Hat jemand versucht, Modifikatoren in Komponententests abzudecken? Beispiel:

    Modifikator nur Besitzer {
        if (msg.sender != Eigentümer) throw;
        _;
    }

Antworten (2)

Ja, es gibt vielleicht eine bessere Möglichkeit, dies auszudrücken, wie man auf Throw-Bedingungen testet - oder jetzt eher assert(), require() und revert(). Im obigen Fall möchten Sie beispielsweise sicherstellen, dass, wenn jemand anderes als der Eigentümer eine Funktion aufruft, die Funktion ausgelöst wird und alle Statusänderungen auf ihren ursprünglichen Zustand zurückgesetzt werden. Der beste Weg, dies zu tun, sind Solidity-Einheitentests mit Truffle. Wenn bei der Verwendung von JavaScript-Unit-Tests eine Throw-Bedingung auftritt, „bricht“ der Test leider ab – mit Solidity-Unit-Tests können Sie viele Throw-Bedingungen gleichzeitig testen, ohne anzuhalten.

Was Sie verwenden möchten, ist ein Proxy-Vertrag, um „den Vertragsaufruf in einen Rohaufruf zu verpacken und zurückzugeben, ob er erfolgreich war oder nicht“. . Ein Proxy-Vertrag sollte wie folgt aussehen:

contract ThrowProxy {
  address public target;
  bytes data;

  function ThrowProxy(address _target) {
    target = _target;
  }

  //prime the data using the fallback function.
  function() {
    data = msg.data;
  }

 function execute() returns (bool) {
    return target.call(data);
  }
}

Bei der Erstellung Ihres throwProxy-Vertrags _targetwäre your die Adresse des Vertrags, den Sie testen möchten.

In Ihren Solidity-Einheitentest würden Sie einen Test wie den folgenden aufnehmen:

function testTheThrow() {
    MyContract mycontract = new MyContract(); 
    ThrowProxy throwproxy = new ThrowProxy(address(mycontract)); 
    MyContract(address(throwproxy)).functionThatShouldThrow();
    bool r = throwproxy.execute.gas(200000)(); 
    Assert.isFalse(r, "Should be false because is should throw!");
}

Im obigen Beispiel verwenden wir die Fallback-Funktion aus dem throwProxy-Vertrag, um die Aufrufdaten zur Ausführung functionThatShouldThrow()von zu kompilieren, indem wir die execute()Funktion aus throwProxy verwenden, um die .call()-Methode auf Ihrem ursprünglichen Ziel zu verwenden, MyContract. Denken Sie daran, dass .call() einen booleschen Wert zurückgibt, ob die Ausführung erfolgreich war oder nicht - es enthält keine Rückgaben von der Funktion. Von hier aus speichern Sie ras bis zum booleschen Wert, ob functionThatShouldThrow()dies erfolgreich war oder nicht. Von hier aus können Sie die Assert.sol-Bibliothek verwenden, um zu behaupten, dass dies rtatsächlich falsch ist, da die Funktion ausgelöst werden sollte.

Ob die Funktion den Modifikator verwendet oder nur die notwendigen Überprüfungen in ihrem Körper durchführt, sind interne Implementierungsdetails der Funktion, die von außen nicht sichtbar sind. Tests sollten sich also nicht darum kümmern. Wenn eine Funktion nur vom Eigentümer des Smart Contracts aufgerufen werden soll, schreiben Sie einen Test, der die Funktion sowohl von Eigentümer- als auch von Nicht-Eigentümerkonten aufruft und überprüft, ob die Anforderung erfüllt ist. Auf diese Weise funktioniert Ihr Test unabhängig davon, ob der Modifikator verwendet oder die Überprüfung im Funktionskörper durchgeführt wird.