In Solidity geschriebene Unit-Tests, wie man msg.sender address, msg.value ändert,

Ich würde gerne wissen, ob es möglich ist, die Adresse des Funktionsaufrufs des Nachrichtensenders des Vertrags beim Schreiben von Einheitentests in Solidität zu ändern. Es sollte wirklich so sein, ich habe versucht herauszufinden wie, konnte es aber nicht.

pragma solidity ^0.4.4;

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";

contract A {

    event Test(address add);

    function test() {
        Test(msg.sender);
    }
}

contract TestA {

    function test01() {
        A a = A(DeployedAddresses.A());
        a.test(); // <--- msg.sender is address(this), but how do we use a different account from testrpc?
    }
}

In Gitter habe ich eine Antwort bekommen, also habe ich versucht, es so auszuführen:

a.test({from: 0xf6a948bff792e4f42d7f17e5e4ebe20871d160f2});

Es gibt den folgenden Fehler:

TypeError: Wrong argument count for function call: 1 arguments given but expected 0. a.test({from: 0xf6a948bff792e4f42d7f17e5e4ebe20871d160f2});

Betriebssystem: Windows 10 Truffle-Version: v3.4.11 Ethereum-Client: testrpc v4.1.3 Knotenversion: v8.7.0 npm-Version: 5.4.2

Antworten (3)

Sie können die Absenderadresse nicht innerhalb von solidity ändern. Die Solidity-Tests werden innerhalb des EVM ausgeführt und erlauben keine Änderung des msg.sender. Es ist möglich, dass eine modifizierte Version des EVM eine solche Funktionalität bereitstellt, aber mir ist eine solche Modifikation nicht bekannt.

Sie können die zu testende Funktion ändern, um einen zusätzlichen Parameter zu akzeptieren, und dort den gewünschten Absender übergeben

contract A {
    // We cannot test directly deposit
    function deposit(uint _amount) public {
        doDeposit(msg.sender, _amount);
    }
    // But we can test doDeposit
    function doDeposit(address _sender) public {
    }
}

contract TestA {
    address constant senderA = "0xA00...";
    address constant senderB = "0xB00...";
    function testDeposit() {
        A a = A(DeployedAddresses.A());
        a.doDeposit(senderA, 10000); 
        a.doDeposit(senderB, 10000); 
    }
}

Es ist nicht ideal, aber es kann helfen, einige Fehler zu finden.

Eine weitere Möglichkeit ist die Verwendung der Testvertragsadresse

contract TestA {
    address constant senderA = "0xA00...";
    address constant senderB = "0xB00...";
    function testMint() {
        // TestA is the owner a
        A a = new A(this);
        // Only the owner TestA can mint
        a.mint(senderA, 10000);
        // make senderA approve TestA
        a.doApprove(senderA, this, 1000);
        // testA can make a transfer from senderA
        a.transferFrom(senderA, senderB, 1000);
    }
}
Gute Idee. Gibt es einen Kommentar dazu, dies zu kapseln, damit es außerhalb des Testvertragsbereichs nicht erreicht werden kann? Eine solche Bereitstellung würde zu vielen Schwachstellen führen oder Code und Testcode müssten vor der Kompilierung auskommentiert werden.
Ich habe gesehen, dass einige Verträge onlyTestModifikatoren haben, die nach einer testVariablen suchen, aber es ist sehr hässlich.
kann jemand einen Weg zeigen, dasselbe zu erreichen, während er remix_tests in der Remix IDE verwendet?
@momoja Es ist besser, dafür eine separate Frage zu erstellen. Niemand wird den Kommentar bemerken.
@Ismael danke, ich habe hier gepostet ethereum.stackexchange.com/questions/127101/…

Da Sie einen Vertrag (TestA) haben, der eine Funktion eines anderen Vertrags (A) aufruft, ist msg.sender immer die Adresse von TestA in der Testfunktion von A, da für Vertrag A die Adresse, die die Nachricht gesendet hat, TestA war.

Wenn Sie die tatsächliche Adresse protokollieren möchten, die die Funktion ursprünglich aufgerufen hat, müssen Sie Folgendes tun:

pragma solidity ^0.4.4;

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";

contract A {

    event Test(address add);

    function test(address _sender) {
        Test(_sender);
    }
}

contract TestA {

    function test01() {
        A a = A(DeployedAddresses.A());
        a.test(msg.sender); 
    }
}
Es ist eine gute Idee. Siehe bitte meinen Kommentar zu Ismael. Außerdem würde dies für die meisten Modifikatoren nicht funktionieren, oder? Ich denke, dass sie auch auf diese Weise geändert werden könnten.

Hier ist ein alternativer Ansatz, den ich effektiv zum Manipulieren msg.senderin Unit-Tests verwendet habe, die in Solidität geschrieben sind:

  1. Erstellen Sie „Akteur“-Verträge, d. h. Verträge, die ein Unit-Test-Actor-Verhalten implementieren und Aufrufe an den zu testenden Vertrag (Contract Under Test, CUT) senden.
  2. Stellen Sie einen Akteursvertrag für jede einzelne Adresse bereit, die Sie zum Schreiben Ihrer Komponententests benötigen. Wenn Sie beispielsweise Testfälle für einen ERC20-Vertrag schreiben, können Sie a SenderContractund a implementieren ReceiverContract, jeder hat seine eigene Adresse und wenn sie die CUT-Funktionen aufrufen, msg.senderwerden sie auf ihre bereitgestellten Adressen gesetzt
  3. Wenn Sie jetzt Unit-Tests schreiben, anstatt die CUT-Funktionen direkt aufzurufen, erstellen Sie den Testfall als eine Folge von Actor-Funktionsaufrufen ( msg.senderhält die Adresse des Actor-Vertrags in diesen Aufrufen).