Cómo probar modificadores unitarios en Solidity

Estoy usando https://github.com/dapphub/dapp framework para escribir contratos de Solidity y su marco de prueba de unidad ds-test .

¿Alguien ha tratado de cubrir los modificadores en las pruebas unitarias? Ejemplo:

    modificador soloPropietario {
        if (mensaje.remitente!= propietario) throw;
        _;
    }

Respuestas (2)

Sí, hay, quizás una mejor manera de expresar esto es cómo probar las condiciones de lanzamiento, o ahora, más bien afirmar (), requerir () y revertir (). Por ejemplo, en el caso anterior, desea asegurarse de que cuando alguien que no sea el propietario llama a una función, la función se inicia y cualquier cambio de estado se revierte a su estado original. La mejor manera de hacer esto es con las pruebas unitarias de Solidity usando Truffle. Desafortunadamente, cuando se usan pruebas unitarias de JavaScript, cuando se encuentra una condición de lanzamiento, la prueba se "interrumpe". Con las pruebas unitarias de Solidity, puede probar muchas condiciones de lanzamiento al mismo tiempo sin detenerse.

Lo que querrá usar es un contrato de proxy para "envolver la llamada del contrato en una llamada sin formato y devolver si tuvo éxito o no". . Un contrato de representación debe tener el siguiente aspecto:

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

En la creación de su contrato throwProxy, su _targetsería la dirección del contrato que le gustaría probar.

En su prueba de unidad de Solidez, incluiría una prueba como la siguiente:

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

En el ejemplo anterior, usamos la función alternativa del contrato throwProxy para compilar los datos de la llamada y ejecutarlos functionThatShouldThrow()usando la execute()función de throwProxy para usar el método .call() en su objetivo original, MyContract. Recuerde que .call() devuelve un booleano sobre si la ejecución es exitosa o no; no incluye ningún retorno de la función. A partir de aquí, guarde el rvalor booleano en cuanto a si functionThatShouldThrow()tiene éxito o no. Desde aquí, puede usar la biblioteca Assert.sol para afirmar que r, de hecho, es falso porque la función debería haberse lanzado.

Si la función usa un modificador o simplemente realiza las comprobaciones necesarias en su cuerpo, son detalles de implementación internos de la función que no son visibles desde el exterior. Así que las pruebas no deberían preocuparse por esto. Si solo el propietario del contrato inteligente debe poder llamar a alguna función, escriba una prueba que llame a la función desde las cuentas del propietario y del no propietario, y verifique que se cumpla el requisito. De esta manera, su prueba funcionará independientemente de si se usa el modificador o si se realiza una verificación en el cuerpo de la función.