Pruebas básicas con Truffle (sin cambiar el estado del contrato)

Estoy empezando a usar Truffle para probar este contrato

pragma solidity ^0.4.11;

contract Basic {
    bytes32 value;

    function Basic() {
        value = "mcansado";
    }

    function getValue() constant returns(bytes32) {
        return value;
    }

    function setValue(bytes32 _value) constant returns(bytes32) {
        value = _value;
    }
}

El código de prueba relevante es

it("Should set value to 40", function(done) {
    basic.setValue(40, {from:accounts[0], to:basic.address})
    .then(function(tx) {
      console.log(tx)
      //assert.isOk(tx.receipt)
      done()
    }, function(error) {
        assert.equal(true, false)
        console.error(error)
        done()
      })
  })

A esa prueba le sigue otra para obtener value. Esperaba recuperar 40, pero en cambio obtengo este resultado

Contract: Basic
0x7d32e47118fbc082af1350062f10efee2694ff15Should retrive deployed contract.
0x0000000000000000000000000000000000000000000000000000000000000000Should set value to 40 (43ms)
mcansado // returns the value made by constructor, not 40Should return the value set as 40


  3 passing (114ms)

¿Cómo puedo enviar el nuevo valor en la prueba?

Respuestas (1)

Hay un par de problemas en su contrato y su prueba:

- Contrato de Solidez

Debe diferenciar una llamada (método de solo lectura) de una transacción (método de escritura que cambia el estado). La palabra clave constantse usa para especificar el método como readOnly, lo que significa que no se manipulan variables de estado.

Además, una transacción siempre es asíncrona porque la transacción primero debe transmitirse a la red peer2p y luego ser extraída por un minero, esto podría llevar tiempo (especialmente en una red real como testnet o mainnet).

Por lo tanto, no puede esperar que se devuelva ningún valor cuando envía la transacción desde el exterior (Web3 ans Truffle).

El contrato quedaría así:

pragma solidity ^0.4.11;

contract Basic {
    bytes32 value;

    function Basic() {
        value = "mcansado";
    }

    function getValue() constant returns(bytes32) {
        return value;
    }

    function setValue(bytes32 _value)  {
        value = _value;
    }
}

- Prueba de Trufa

En segundo lugar, su prueba no es correcta porque no puede esperar un valor devuelto de la transacción, debe llamar getValue.call()después de que se haya enviado la transacción.

Otro pensamiento, con byte32el tipo, debe tratar con el valor hexadecimal. Por lo tanto, debe usar las funciones web3 web3.fromAsciiy web3.toAscii.

Último punto, puede llamar directamente Basic.deployed()para obtener la instancia implementada.

Adapté tu prueba:

var Basic = artifacts.require("./Basic.sol");

contract('Basic', function(accounts) {

    var basic;

    it("Should set value to 40", function() {

        return Basic.deployed().then(function(instance) { // Get deployed contract
            basic = instance;

            return basic.getValue.call(); // call getValue function

        }).then(function(result) {
            console.log("#######################");
            console.log("result (hexa)=" + result); // in hexa
            console.log("result (ascii)=" + web3.toAscii(result)); // in ascii

            return basic.setValue(web3.fromAscii("40"), {from: accounts[0]}); // send transaction setValue function

        }).then(function(receipt) {
            console.log("#######################");
            console.log("transaction receipt");
            console.log(receipt);

            return basic.getValue.call(); // call getValue function

        }).then(function(result) {
            console.log("#######################");
            console.log("result (hexa)=" + result); // in hexa
            console.log("result (ascii)=" + web3.toAscii(result)); // in ascii
            assert.equal(web3.toAscii(result), "40");
        });
    });


});

Y aqui esta el resultado:

  Contract: Basic
#######################
result (hexa)=0x6d63616e7361646f000000000000000000000000000000000000000000000000
result (ascii)=mcansado
#######################
transaction receipt
{ tx: '0x051654a9fc0aaeb44ff54229c31ab91e9ad9fe9b03da4498d978740e760d739c',
  receipt:
   { transactionHash: '0x051654a9fc0aaeb44ff54229c31ab91e9ad9fe9b03da4498d978740e760d739c',
     transactionIndex: 0,
     blockHash: '0x106da8c6862f2caf94d40cf866d4b9a61b9c7839d7608fab00e114700dc3eb93',
     blockNumber: 108,
     gasUsed: 26695,
     cumulativeGasUsed: 26695,
     contractAddress: null,
     logs: [] },
  logs: [] }
#######################
result (hexa)=0x3430000000000000000000000000000000000000000000000000000000000000
result (ascii)=40

Publiqué el proyecto completo en GitHub aquí para obtener más detalles.

Esto es una locura, ¡gracias por la respuesta detallada! Aprendí una tonelada.
Comentario muy útil, estaba enfrentando algunos de los mismos problemas. Todavía no entiendo por qué se usa getValue.call() mientras que setValue() se llama directamente. Aún así, seguir este patrón de llamar a la función directamente cuando necesito una transacción me funcionó como lo hace arriba.
Tengo el mismo problema, pero con su solución no he estado disponible para solucionarlo. La prueba en Solidity funciona perfectamente, pero en javascript la variable de estado no cambiará. github.com/trabajo-en-bloques/echo-blockchain