Once we have written our contracts, or as we are writing them, it is good to check that they meet our expectations, that they do what they are supposed to do.
There are multiple ways of doing this, but in this section we limit ourselves to testing. Testing involves the execution of our contract (or part of it) to check if certain property holds, and it can be manual or automated.
When we want to test a contract written in LIGO, we have two options:
we compile our code to Michelson and test the compiled code
we use LIGO specific tools to test our LIGO code
There are multiple frameworks for testing Michelson contracts, we will not get into details, but here is a list of tutorials showing how to test contracts in Michelson:
Another alternative is to use Tezos's binary
directly. There's a new
mockup mode which is does
not need a Tezos node to be running (albeit this is less similar to
mainnet than running a Tezos sandboxed node).
We show the main steps that need to be done to use the mockup mode to test our LIGO contracts. As a first step, we need to compile our LIGO contract to Michelson code. Suppose we write the following simple contract:
To obtain Michelson code from it, we run the LIGO compiler:
Instead of outputting the resulted compiled code in the screen, we can
tell LIGO to write it in a file called
Now it is time to test this Michelson code we obtained: we want to execute it using the mockup mode.
Before anything, make sure you have installed
tezos-client, a simple
way to do so is by using opam (
opam install tezos-client).
We can list all the protocols available using
mockup protocols. In this example, we will use Edo for testing, so
the command we use for creating a mockup instance on the directory
This command returns a list of Tezos addresses that we can use with the client in subsequent commands. As recommended in the Tezos documentation, we can add a shell alias to avoid mistakes:
We can list the addresses returned above by running:
We are now ready to originate (or "deploy") the contract on our mockup Tezos:
--init argument (
"foo") is the initial storage for our
deployed contract. In case we had a more complex storage, we could
have used LIGO's
compile-storage sub-command to compile a LIGO
expression to a Michelson storage.
Now it is time to test! The property we want to check is that if we
Append ("bar") on our contract with storage
the contract updates its storage to
As a first sanity check, we can confirm that the storage is currently
Then, we execute a call to our contract with parameter
("bar"). To do so, we first compile the parameter as follows:
So our parameter is simply the string (notice that the constructor
Append was removed). We execute a call to the contract with this
compiled parameter as follows:
We have chosen
bootstrap2 as the origin of this call (for no
particular reason, any address could do).
We can finally check that that our property holds: the storage is now "foobar":
Good! Our contract passed the test successfully!
The LIGO command-line interpreter provides sub-commands to test directly your LIGO code. The three main sub-commands we currently support are:
We will show how to use the first two, while an example on how to use the third one was already explained in the here.
interpret allows to interpret an expression in a
context initialised by a source file. The interpretation is done using
Let's see how it works on an example. Suppose we write the following contract which we want to test.
This contract keeps an integer as storage, and has three entry-points:
one for incrementing the storage, one for decrementing the storage,
and one for resetting the storage to
As a simple property, we check whether starting with an storage of
10, if we execute the entry-point for incrementing
32, then we get
a resulting storage of
42. For checking it, we can interpret the
With the argument
--init-file we pass the contract we want to test,
and the sub-command requires also the expression to evaluate in that
context, in this case, a call to our contract (
main) with parameter
Increment (32) and storage
10. As a result, we can check that the
resulting storage is
42 (the second component of the pair), and
there are no further operations to execute (the first component).
We can tune certain parameters of the execution by passing them as arguments:
test can be used to test a contract using LIGO. It
interpret as in this case we can describe the test
internally using LIGO code, and no Michelson code is actually
⚠️ Please keep in mind that this sub-command is still BETA, and that there are features that are work in progress and are subject to change. No real test procedure should rely on this sub-command alone.
Resuming the example we used in the explanation for
add a new LIGO entry that uses the extra primitives provided by
to test the contract above. This time we will simulate that the
contract is actually deployed to an address, and check inside LIGO
that the resulting storage is
42 after executing a call to
Notice that now we wrote the property inside LIGO, using:
Test.originateto deploy a contract.
Test.external_callto simulate an external call.
Test.get_storageto check the storage from a contract.
A property like
testme is a definition of a boolean value. The
test evaluates a test, and returns whether it was
successful or not (i.e. returned
The extra features we can use in LIGO when using the sub-command
test are the following:
Test.originate c stbinds contract
cwith the address
addrwhich is returned,
stas the initial storage.
Test.set_now tsets the current time to
Test.set_balance addr bsets the balance of contract bound to address
Test.external_call addr p amtperforms a call to contract bound to
Test.get_storage addrreturns current storage bound to address
Test.get_balancereturns current balance bound to address
Test.assert_failure (f : unit -> _)returns
xinto the console.