---
schema_version: "1"
id: eda0b5c35c873a96fa94ea29aa88193fe122f27c7f529577bae08673ee562865
title: BDD Test-Writing Syntax Reference
collection: mulesoft
version: current
locale: en-us
portal_url: https://docs.salesforce.com/mulesoft/current/en-us/api-functional-monitoring/bat-bdd-reference.md
canonical_url: https://docs.mulesoft.com/api-functional-monitoring/bat-bdd-reference
source_site: docs.mulesoft.com
content_type: documentation
content_hash: 9a978cb6047a3b0f6e9cf41a858f671d9bdb08d38e2ceb5895c94f6ec1f88cc8
description: MuleSoft Documentation Site
latest: true
---
---
product: API Functional Monitoring
---

# BDD Test-Writing Syntax Reference

> For the full documentation index, see: https://docs.mulesoft.com/llms.txt

Behavior Driven Development (BDD) is the syntax for writing BAT tests for processing in DataWeave.
BDD is an embedded domain specific language (EDSL) that resembles other testing frameworks, such as
Mocha and Jasmine.

The following statement is required in each BAT test:

`import * from bat::BDD`

This statement imports the Domain Specific Language (DSL) testing library BDD.dwl, which defines
words you frequently use when writing, such as describe, it, GET, POST, and sleep).

This statement imports common matchers, such as mustEqual, mustMatch, every, oneOf, and assert.

The following example shows how you typically begin writing a test:

```text
import * from bat::BDD
import * from bat::Assertions
import * from bat::Mutable


var context = HashMap()
---
describe("the login flow") in [
  it("tries a secured endpoint") in [
    GET `http://127.0.0.1:4567/secured_by_token` with {

    } assert [
      $.response.status mustEqual 401,
    ]
  ],
  it("gets the access token") in [
    POST `http://127.0.0.1:4567/get_access_token` with {} assert [
      $.response.body.new_token mustMatch /accessToken_\d+/,
    ] execute [
      context.set('token', $.response.body.new_token)
    ] assert [
      context.get('token') mustMatch /accessToken_\d+/,
      context.get('token') mustEqual $.response.body.new_token,
      $.response.status mustEqual 200,
    ]
  ],
  it("tries to get a secured endpoint") in [
    GET `http://127.0.0.1:4567/secured_by_token/header` with {
      headers: {
        Authorization: context.get('token')
      }
    } assert [
      $.request.headers.Authorization mustEqual context.get('token'),
      $.response.status mustEqual 200
    ]
  ]
]
```

## About Test Files

Create a `.dwl` file for each functional scenario. A folder-based organization of files is
recommended. This organization accommodates reports the BAT testing generates. For example:

tests ├── CoreServices │ └── Sanity.dwl └── DesignCenter ├── APIDesigner │ └── Designer.dwl └──
MyFolder ├── DataSense.dwl └── GetProjects.dwl

A test file must contain a `describe` expression.

import \* from bat::BDD
---

describe \`Demo scenario\` in \[

\]

A test suite must contain at least one test (.dwl) file.

## Keeping Confidential Information Secure in Tests

In your tests, you can access shared secrets from Anypoint Secrets Manager. Secrets Manager enables
you to securely store sensitive information, such as a password, authentication token, endpoint URL,
or webhook URL.

### Limitations

- Functional Monitoring works only with symmetric key shared secret types from Anypoint Secrets
  Monitor.

- You can use aliases for shared secrets in a test suite only if you plan to run that test suite
  from a private location.

### Configure a Secret in Anypoint Secret Manager

To keep sensitive information secret in tests you run from a private location, create a shared
secret in Secrets Manager.

To configure a shared secret:

1.  Open a secrets group or create a new one. Create the group in the same environment that you are
    using in BAT CLI.

    To find out which environment you are using in BAT CLI:

    1.  Run the command `bat whoami`.

        The output has the ID for the environment.

    2.  Run the command `bat environment ls` to list the environments to which you have access.

    3.  Match the ID from the `bat whoami` command with one of the environments listed.

    4.  If you need to switch to the environment that your secrets group is in, run the command
        `bat environment switch name`, where `name` is the name of the environment.

2.  Select **Shared Secret**.

3.  In the **Type** field, select **Symmetric Key**.

4.  In the **Key** field, paste the sensitive information encoded as a Base64 string.

5.  Paste the Base64 string into the **Confirm Key** field.

After you modify the monitor’s `main.dwl` file to add the secret information to the code, grant the
monitor access to the secrets you configured in Secrets Manager. See
[Grant Your Monitor Access to the Secret](#grant-access-to-secret).

### Grant Your Monitor Access to the Secret

After you modify your monitor to add the secret information, grant the monitor access to the secret.
At runtime, BAT CLI looks up the shared secrets using the aliases.

To grant a monitor access to the secret:

1.  Copy the name of the new shared secret obtained in
    [Configure a Secret in Anypoint Secret Manager](#configure-secret).

2.  At a command prompt, run the `bat grant` command, specifying an alias for the shared secret.
    When you run this command, BAT CLI creates a section named `secrets` in your test suite’s
    `bat.yaml` file, if the section does not already exist. In that section, BAT CLI adds these
    indented lines:

    alias: secretId: "secret-ID"

    - `alias`: The alias that you specified in the `bat grant` command.

    - `secret-ID`: The ID of the secret within Anypoint Secrets Manager. This ID does not appear in
      ASM, so there is no way for someone looking in your `bat.yaml` file to associate the ID with
      any particular secret. The BAT CLI uses this ID to look up the secret that you associated with
      the alias.

### Example of Using an Alias

Use the alias in a test by storing it in a variable, as in this example:

import \* from bat::BDD import \* from bat::Assertions

var mySecret: String = secret('myAlias') default 'notFound'

---

suite(parts="Simple Suite") in \[ it must 'answer 200' in \[ GET '$(config.url)?token=$(mySecret)'
with {} assert \[ $.response.status mustEqual 200 \] execute \] \]

`mySecret`

The variable in which the secret is stored in this example. The variable is declared as a String.

`secret('myAlias')`

The `secret()` function requires the input `'name-of-alias'`, where `name-of-alias` is the alias of
the shared secret that you want to use.

`default 'notFound'`

The message to show if a shared secret with the specified alias does not exist in Anypoint Secrets
Manager.

`$(mySecret)`

The use of the variable `mySecret` to supply the authentication token for the endpoint at the URL
that is defined in the configuration file that was specified when the `bat` command to run the test
suite was entered.

For example, suppose that the configuration file was this:

The example configuration file dev-environment.dwl

{ url: "https://dev.yourcompany.com/shoppingCart" }

In this case, the command to run this test suite, when the command is run in the directory in which
the `bat.yaml` file for the test suite is located and the default profile is used, is this:

bat --config=dev-environment.dwl

At runtime, the BAT CLI replaces the variable with the shared secret that it finds associated with
the specified alias in Anypoint Secrets Manager.

## Test Blocks

Test blocks make the test more readable. You can write every test block as a function call or a
custom interpolation.

### Test Keywords

You use the following keywords and follow Fowler’s _GivenWhenThen_ structure, in tests:

<table><colgroup><col> <col> <col></colgroup><thead><tr><th>Function Name</th><th>Description</th><th>Stops execution if it fails</th></tr></thead><tbody><tr><td><div><div><p><code>describe</code></p></div></div></td><td><div><div><p>For grouping, which you can nest as deep to add contextual information for reports</p></div></div></td><td><div><div><p>No</p></div></div></td></tr><tr><td><div><div><p><code>scenario</code></p></div></div></td><td><div><div><p>Same as describe</p></div></div></td><td><div><div><p>No</p></div></div></td></tr><tr><td><div><div><p><code>suite</code></p></div></div></td><td><div><div><p>Same as describe</p></div></div></td><td><div><div><p>No</p></div></div></td></tr><tr><td><div><div><p><code>given</code></p></div></div></td><td><div><div><p>Test step, used for preparation</p></div></div></td><td><div><div><p>Yes</p></div></div></td></tr><tr><td><div><div><p><code>when</code></p></div></div></td><td><div><div><p>Test step, normally used to create side effects</p></div></div></td><td><div><div><p>Yes</p></div></div></td></tr><tr><td><div><div><p><code>it</code></p></div></div></td><td><div><div><p>Test step, validations</p></div></div></td><td><div><div><p>No</p></div></div></td></tr><tr><td><div><div><p><code>should</code></p></div></div></td><td><div><div><p>Test step</p></div></div></td><td><div><div><p>No</p></div></div></td></tr><tr><td><div><div><p><code>must</code></p></div></div></td><td><div><div><p>Test step</p></div></div></td><td><div><div><p>Yes</p></div></div></td></tr><tr><td><div><div><p><code>it should "str"</code></p></div></div></td><td><div><div><p>Test step</p></div></div></td><td><div><div><p>No</p></div></div></td></tr><tr><td><div><div><p><code>it must ""</code></p></div></div></td><td><div><div><p>Test step</p></div></div></td><td><div><div><p>Yes</p></div></div></td></tr><tr><td><div><div><p><code>while</code></p></div></div></td><td><div><div><p>Test step</p></div></div></td><td><div><div><p>No</p></div></div></td></tr><tr><td><div><div><p><code>until</code></p></div></div></td><td><div><div><p>Test step</p></div></div></td><td><div><div><p>No</p></div></div></td></tr></tbody></table>

### About a Test Block

Test blocks have a shorthand name to skip the block described as `x<name>`. For example, the skipped
version of `describe` is `xdescribe`.

```text
describe("A flow")  in [ ... ] // Describes a sequence of test blocks
xdescribe("A flow") in [ ... ] // The same, but skipped.

describe `A flow` in [ ... ]   // The same as describe, but with a custom interpolation
xdescribe `A flow` in [ ... ]  // The same, but skipped.
```

### About Custom Interpolators

Custom interpolators provide a way to call functions and decompose interpolations in two lists:

- The first list contains all the string literals.

- The second one contains the interpolated values.

You do not need to convert the values to strings. Enclose a custom interpolation text and value in
backticks (`` ` ``).

Every item in the following block can be used as custom interpolators and has the `x<name>` version.

```text
import * from bat::BDD         // <-----
import * from bat::Assertions
---
describe `User trades stocks` in [
  scenario `User requests a sell before close of trading` in [
    given `I have 100 shares of MSFT stock` in [
      POST `http://broker/create_stocks` with {
        body: {
          quantity: 100,
          paper: 'MSFT'
        }
      } assert [
        $.response.status == 201
      ]
    ],
    given `I have 150 shares of APPL stock` in [
      POST `http://broker/create_stocks` with {
        body: {
          quantity: 150,
          paper: 'APPL'
        }
      } assert [
        $.response.status == 201
      ]
    ],
    when `I ask to sell 20 shares of MSFT stock` in [
      POST `http://broker/sell_stocks` with {
        body: {
          quantity: 20,
          paper: 'MSFT'
        }
      } assert [
        $.response.status == 201
      ]
    ],
    it should "have 80 shares of MSFT stock" in [
      GET `http://broker/get_stocks/MSFT` with {
        headers: {}
      } assert [
        $.response.status == 200,
        $.response.body.quantity == 80
      ]
    ],
    it should "have 150 shares of APPL stock" in [
      GET `http://broker/get_stocks/APPL` with {
        headers: {}
      } assert [
        $.response.status == 200,
        $.response.body.quantity == 150
      ]
    ]
  ]
]
```

You can also write the block without custom interpolators to conform to your coding style guide.
This doesn’t affect behavior:

```text
import * from bat::BDD         // <-----
import * from bat::Assertions
---
describe("User trades stocks") in [
  scenario("User requests a sell before close of trading") in [
    given("I have 100 shares of MSFT stock") in [
      POST `http://broker/create_stocks` with {
        body: {
          quantity: 100,
          paper: 'MSFT'
        }
      } assert [
        $.response.status == 201
      ]
    ],
    given("I have 150 shares of APPL stock") in [
      POST `http://broker/create_stocks` with {
        body: {
          quantity: 150,
          paper: 'APPL'
        }
      } assert [
        $.response.status == 201
      ]
    ],
    when("I ask to sell 20 shares of MSFT stock") in [
      POST `http://broker/sell_stocks` with {
        body: {
          quantity: 20,
          paper: 'MSFT'
        }
      } assert [
        $.response.status == 201
      ]
    ],
    should("have 80 shares of MSFT stock") in [
      GET `http://broker/get_stocks/MSFT` with {
        headers: {}
      } assert [
        $.response.status == 200,
        $.response.body.quantity == 80
      ]
    ],
    should("have 150 shares of APPL stock") in [
      GET `http://broker/get_stocks/APPL` with {
        headers: {}
      } assert [
        $.response.status == 200,
        $.response.body.quantity == 150
      ]
    ]
  ]
]
```

## Controlling Execution and Deleting Assets

If you get a failure in the middle of a test, you need to delete any created assets. For example,
the user creates an asset, performs a validation, and then deletes it. Typically, that validation
fails, and since it breaks the test, the asset is not deleted and your database starts accumulating
test data. Typically this means changing a `must` to a `should` so that execution can continue, but
not leave a failed asset.

Incorrect Example:

If the update name in line 6 fails, the project is not deleted because the execution stops.

```text
describe `update project names` in [
  it must 'create a project' in [
    createProject()     // OK
  ],
  it must 'update the name' in [
    updateProjectName() // FAILS
  ],
  // Because the previous step is a `must` that failed, execution stops here and the next steps don't execute
  it must 'clean up deleting the project' in [
    deleteProject()     // CANCELLED
  ]
]
```

Use these reserved words to wrap steps to stop or allow execution to continue:

- `should` means something might fail, but it is not mandatory for the test.

- `must` means that something, such as project creation, must execute to continue.

Correct Example:

```text
describe `update project names` in [
  it must 'create a project' in [
    /**
     * Project creation is a MUST, because in this scenario
     * we depend on the created project to continue.
     */
    createProject()     // OK
  ],
  it should 'update the name' in [
    /**
     * Validations are should because the execution must continue
     * if the validation fails.
     */
    updateProjectName() // FAILS
  ],
  // Because the previous step is a should and it failed, continue executing.
  it must 'clean up deleting the project' in [
    deleteProject()     // OK
  ]
]
```

## Executing Steps Selectively

The `assuming` function skips the test if the result is false. This command has the following
syntax:

`[TestBlockExpression] assuming [BooleanExpression] in …​`

For example:

```text
describe `E2E Scenario` in [
  it should 'always do something' in [
    doSomething()
  ],
  it should 'do something else' in [
    doSomethingElse()
  ],
  it should 'sometimes, do something else' assuming (random() > 0.5) in [
    // This is executed randomly, based on          ^^^^^^^^^^^^^^^^ that condition
    doSomethingElse()
  ],
  it should 'do something in dev environments' assuming (config.env == 'DEV') in [
    // This is executed only when                       ^^^^^^^^^^^^^^^^^^^^^ that == true
    doSomethingElse()
  ]
]
```

To make the code more readable and understandable, you can use two aliases for this function. `when`
and `whenNot`. For example:

```text
describe `E2E Scenario` in [
  it should 'always do something' in [
    doSomething()
  ],
  it must 'do something else' when config.runSanity in [
    doSomethingElse()
  ],
  it should 'do something else' when a == b in [
    doSomethingElse()
  ],
  it should 'do something in dev environments' whenNot config.isSmokeTests in [
    doSomethingElse()
  ]
]
```

## Executing Loop Sentences

The while or until functions run the test while (or until) a condition becomes true or false.

Signature of the while function:

- `while( sentence , condition, time per request, number of retries)`

- `do { sentence } while (condition) //→ Default values: 1 second and 3 retries`.

Signature for the until function:

- `until( sentence , condition, time per request, number of retries)`

- `do { sentence } until (condition) //→ Default values: 1 second and 3 retries`.

Example:

```java
dwl
import * from bat::BDD
import * from bat::Assertions
import * from bat::Types
---
suite("Example for until and while") in [
  it should 'test the while prefix' in [
    while(() -> GET `http://apimon.cloudhub.io/users` with {},
    (x: BATHttpStep) -> x.result.response.status != 200, 10000, 5)
  ],
  it should 'test the while infix' in [
    do {
      () -> GET `http://apimon.cloudhub.io/users` with {} assert [
          $.response.status mustEqual 200
        ]
    } while ($.response.status != 200)
  ],
  it should 'test the until prefix' in [
    until(() -> GET `http://apimon.cloudhub.io/users` with {},
     (x: BATHttpStep) -> x.result.response.status != 200, 10000, 5)
  ],
  it should 'test the until infix' in [
    do {
      () -> GET `http://apimon.cloudhub.io/users` with {} assert [
          $.response.status mustEqual 200
        ]
    } until ($.result.response.status != 200)
  ]
]
```

## See Also

- [MuleSoft Trailblazer Community](https://trailhead.salesforce.com/trailblazer-community/neighborhoods/mulesoft)

- [Salesforce Help](https://help.salesforce.com)

- [Using Secrets to Mask Sensitive Information in Monitors](https://docs.mulesoft.com/api-functional-monitoring/afm-mask-info-in-monitors)
