Testing DAML using scenarios¶
DAML has a built-in mechanism for testing templates called scenarios.
Scenarios emulate the ledger. You can specify a linear sequence of actions that various parties take, and these are evaluated in order, according to the same consistency, authorization, and privacy rules as they would be on the sandbox ledger or ledger server. DAML Studio shows you the resulting Transaction graph.
For more on how scenarios work, see the Examples below.
On this page:
example = scenario do
scenario emulates the ledger, in order to test that a DAML template or sequence of templates are working as they should.
It consists of a sequence of transactions to be submitted to the ledger (after
do), together with success or failure assertions.
-- Creates an instance of the Payout contract, authorized by "Alice" submit alice do
The submit function attempts to submit a transaction to the ledger on behalf of a
submitMustFail alice do exercise payAlice Call
The submitMustFail function asserts that submitting a transaction to the ledger would fail.
This is essentially the same as
submit, except that the scenario tests that the action doesn’t work.
When you load a file that includes scenarios into DAML Studio, it displays a “Scenario results” link above the scenario. Click the link to see a representation of the ledger after the scenario has run.
A very simple scenario looks like this:
example = scenario do -- Creates the party Alice alice <- getParty "Alice" -- Creates an instance of the Payout contract, authorized by "Alice" submit alice do create Payout -- There’s only one party: "Alice" is both the receiver and giver. with receiver = alice; giver = alice
In this example, there is only one transaction, authorized by the party
Alice (created using
getParty "Alice"). The ledger update is a
create, and has to include the arguments for the template (
Payout with receiver = alice; giver = alice).
This example tests a contract that gives both parties an explicit opportunity to agree to their obligations.
example = scenario do -- Bank of England creates a contract giving Alice the option -- to be paid. bankOfEngland <- getParty "Bank of England" alice <- getParty "Alice" payAlice <- submit bankOfEngland do create CallablePayout with receiver = alice; giver = bankOfEngland -- Alice exercises the contract, and receives payment. submit alice do exercise payAlice Call
In the first transaction of the scenario, party
bankOfEngland (created using
getParty "Bank of England") creates an instance of the
CallablePayout contract with
alice as the receiver and
bankOfEngland as the giver.
When the contract is submitted to the ledger, it is given a unique contract identifier of type
payAlice <- assigns that identifier to the variable
In the second statement,
exercise payAlice Call, is an exercise of the
Call choice on the contract instance identified by
payAlice. This causes a
Payout agreement with her as the
receiver to be written to the ledger.
The workflow described by the above scenario models both parties explicitly exercising their rights and accepting their obligations:
"Bank of England"is assumed to know the definition of the
CallablePayoutcontract template and the consequences of submitting a contract instance to the ledger.
"Alice"is assumed to know the definition of the contract template, as well as the consequences of exercising the
Callchoice on it. If
"Alice"does not want to receive five pounds, she can simply not exercise that choice.
Because exercising a contract (by default) archives a contract, once party
"Alice" exercises the
Call choice, she will be unable to exercise it again.
To test this expectation, use the
exampleDoubleCall = scenario do bankOfEngland <- getParty "Bank of England" alice <- getParty "Alice" -- Bank of England creates a contract giving Alice the option -- to be paid. payAlice <- submit bankOfEngland do create CallablePayout with receiver = alice; giver = bankOfEngland -- Alice exercises the contract, and receives payment. submit alice do exercise payAlice Call -- If Alice tries to exercise the contract again, it must -- fail. submitMustFail alice do exercise payAlice Call
Call choice is exercised, the contract instance is archived. The
fails keyword checks that if
exercise payAlice Call again, it would fail.