---
title: Testing MultiversX (former Elrond) Smart Contracts | &‌amp
description: An introduction to the Given-When-Then pattern, followed by instructions on how to use that pattern to test smart contracts.
image: https://miro.medium.com/v2/resize:fit:1400/1*7QzI18A7wTLO92bwFm1_7w.png
---

[Skip to content](https://insights.andamp.io/blog/testing-multiversx-former-elrond-smart-contracts#main-content)

[![andamp logo black (ampersand symbol)](https://insights.andamp.io/hubfs/logo_black.svg "andamp logo black (ampersand symbol)")](https://insights.andamp.io/?hsLang=en)

- [About Us](https://insights.andamp.io/about-us) 
    - [Career](https://insights.andamp.io/career)
    - [Code of Conduct](https://insights.andamp.io/code-of-conduct)
- [Blog](https://insights.andamp.io/blog)

# Testing MultiversX (former Elrond) Smart Contracts

[![](https://insights.andamp.io/hubfs/andamp%20Portraits-Print-Zsolt%20Marton-9.jpg)](https://insights.andamp.io/blog/author/michael-jank)

[Michael Jank](https://insights.andamp.io/blog/author/michael-jank)  26. Januar 2023

T*esting is essential — everybody knows that. Sometimes testing can be hard, and when that's the case, it stops being fun and devs write fewer tests. But testing is super-important when writing smart contracts, as it is the only way to ensure good code quality and avoid bugs (and we all know what *[*bugs*](https://decrypt.co/117695/year-of-the-hacks-biggest-exploits-and-hacks-of-2022)[*in*](https://cointelegraph.com/news/latest-defi-bridge-exploit-results-in-4-4m-losses-for-meter)[*smart*](https://cointelegraph.com/news/ethw-confirms-contract-vulnerability-exploit-dismisses-replay-attack-claims)[*contracts*](https://cointelegraph.com/news/defi-auditor-nets-40-000-for-identifying-uniswap-vulnerability)[*can*](https://decrypt.co/112627/hacker-300k-olympus-dao)[*lead*](https://decrypt.co/112016/mango-dao-solana-defi-hacker-47m-offer)[*to*](https://cointelegraph.com/news/defi-flash-loan-hacker-liquidates-defrost-finance-users-causing-12m-loss)*). I’ll tell you how we test our contracts in a way that makes it a breeze.*

![](https://miro.medium.com/v2/resize:fit:1400/1*7QzI18A7wTLO92bwFm1_7w.png)

Your smart contract should weather any storm (image created with DALL·E)

 

This blog post covers an introduction to the Given-When-Then pattern, followed by instructions on how to use that pattern to test smart contracts. I'll also talk about why we don't use Mandos too much.

# Given-When-What?

Given-When-Then is a popular style to structure test scenarios. The idea is to split the scenario you want to test into three parts:

- **Given:** What is the context of the test? What pre-conditions must be met before the action can be tested?
- **When:** What is tested? Which action is executed?
- **Then:** What is the expected result? What post-conditions should be met?

You can read more about it in [one](https://dannorth.net/introducing-bdd/) [of](https://en.wikipedia.org/wiki/Given-When-Then) [these](https://martinfowler.com/bliki/GivenWhenThen.html) reference explanations.

Let’s put what we learned into Elrond practice.

# Creating our first test

When writing tests, we take a top-down approach. We think of a scenario and break it down into the three phases. Let’s start with an example test for the ping-pong contract.

## “A user can ping.”

We first want to ensure that a user can ping (we leave the pong part as an exercise for the reader).

**What pre-conditions have to be met?**

- A ping-pong contract has to be deployed
- The user must have sufficient EGLD

**What is the action?**

- The user pings

**What do we expect?**

- The ping succeeds
- The user now has x EGLD less
- The contract holds that x EGLD

Ideally, these six statements result in six human-readable lines of code that look similar to this:

Test draft

Well, what can I tell you? It (almost) does.

Actual test code

Now let me show you what’s behind all these functions.

## Some Boilerplate

To write given-when-then functions like this, you need to set up some boilerplate. You can mostly copy our code and only have to apply some minor adaptations. If you're unsure of where to put what, check out our [Github Repo](https://github.com/andamp-europe/elrond-tests-gwt-example).

The core of our testing functions is the *TestSetup* which holds the blockchain, the contract, and the users. It also provides a function to run a test. Don’t worry too much about the definitions of *ContractBase* and *ContractBuilder*. If you’re not a Rust wizard yet, you can take them as they come.

Defining the test setup

Now let’s instantiate the setup:

Deploying the contract

This process is split up into two parts. The first is preparing the setup, and the second is deploying the contract. We want to separate these processes because while the first part is the same for each contract, the second part varies depending on the parameters. The function *given\_a\_deployed\_contract* combines these two parts and is actually the function with which we will start most of our tests.

## Writing actions

The function *when\_pinging* looks like this

Definition of *when\_pinging*

We take the test setup and execute a transaction on it. An important thing here is that we don’t yet check the outcome. We just return the transaction result and leave the assertions to the then part.

## “Then,” we assert

The function to assert how much EGLD a user should have at the end looks like this:

 

Then the user should have EGLD

# Why all the hassle?

You may ask now, why do we jump through all these hoops? The answer is that it pays off quickly. After writing those given-when-then functions, you will soon realize that you can reuse them in many different testing scenarios, almost like putting together lego. This ultimately makes writing tests fun and more intuitive.

**A word on Mandos**

While the idea of Mandos is super cool, it is very cumbersome to write tests. The specification of parameters is quite low-level which makes it especially difficult to write complex tests. Check out the following code snippet for example (taken from [here](https://github.com/multiversx/mx-sdk-rs/blob/master/contracts/examples/bonding-curve-contract/scenarios/deposit.scen.json#L411-L439)):

 

```
"storage": { "...": "...", "str:owned_tokens|address:artist1|str:.info": "u32:2|u32:1|u32:2|u32:2", "str:owned_tokens|address:artist1|str:.node_links|u32:1": "u32:0|u32:2", "str:owned_tokens|address:artist1|str:.node_id|nested:str:MFFT-123456": "1", "str:owned_tokens|address:artist1|str:.value|u32:1": "str:MFFT-123456", "str:owned_tokens|address:artist1|str:.node_links|u32:2": "u32:1|u32:0", "str:owned_tokens|address:artist1|str:.node_id|nested:str:MFNFT-567890": "2", "str:owned_tokens|address:artist1|str:.value|u32:2": "str:MFNFT-567890", "str:owned_tokens|address:artist2|str:.info": "u32:1|u32:1|u32:1|u32:1", "str:owned_tokens|address:artist2|str:.node_links|u32:1": "u32:0|u32:0", "str:owned_tokens|address:artist2|str:.node_id|nested:str:MFSFT-246802": "1", "str:owned_tokens|address:artist2|str:.value|u32:1": "str:MFSFT-246802"},
```

 

This snippet shows what’s necessary to define two users owning some tokens. The corresponding [definition of the storage mapper](https://github.com/multiversx/mx-sdk-rs/blob/master/contracts/modules/src/bonding_curve/utils/storage.rs#L17-L18) looks like this:

 

```
#[storage_mapper("owned_tokens")]fn owned_tokens(&self, owner: &ManagedAddress) -> SetMapper<TokenIdentifier>;
```

 

Don’t get me wrong, a responsible MultiversX developer should fundamentally understand how data is stored in the smart contract to choose the right data structure and program as cost-efficient as possible but it should not be necessary to understand in detail how a SetMapper saves its data to write tests. In our proposed testing style, the definition would look something like this:

 

```
given_user_has_tokens(setup, user1, "MFFT-123456", &[1]);given_user_has_tokens(setup, user1, "MFNFT-567890", &[2]);given_user_has_tokens(setup, user2, "MFSFT-246802", &[1]);
```

# It's time to build!

You can check out the source code of the example contract in [this Github Repo](https://github.com/andamp-europe/elrond-tests-gwt-example). We at [&amp](https://andamp.io/) write Elrond Contracts (and other Web3 stuff, too!). If you’re feeling stuck or just need an extra set of hands, we’re happy to bring your project to the moooon. 🚀

[Testing](https://insights.andamp.io/blog/tag/testing) [Blockchain Development](https://insights.andamp.io/blog/tag/blockchain-development) [MultiversX](https://insights.andamp.io/blog/tag/multiversx) [Elrond](https://insights.andamp.io/blog/tag/elrond) [Smart Contracts](https://insights.andamp.io/blog/tag/smart-contracts)

## Read On

[![](https://miro.medium.com/v2/resize:fit:700/1*UFkzEEmfRMaD7WoN9njI4A.png)](https://insights.andamp.io/blog/how-to-set-up-synpress-for-web3-dapp-frontend-test-automation-with-metamask?hsLang=en)

### [How to set up Synpress for Web3 dApp Frontend Test Automation with MetaMask](https://insights.andamp.io/blog/how-to-set-up-synpress-for-web3-dapp-frontend-test-automation-with-metamask?hsLang=en)

 Setup, configuration, and example tests using Synpress / Cypress for end-to-end frontend test automation of a Web3 dApp with MetaMask login.

[![Why We Chose CDKTF Over HCL for Our Infrastructure](https://miro.medium.com/v2/resize:fit:700/1*oCrShpkC0v0AJ9ijBEswAQ.jpeg)](https://insights.andamp.io/blog/why-we-chose-cloud-development-kit-for-terraform-over-hashicorp-configuration-language-for-our-infrastructure?hsLang=en)

### [Why We Chose Cloud Development Kit for Terraform Over HashiCorp Configuration Language for Our Infrastructure](https://insights.andamp.io/blog/why-we-chose-cloud-development-kit-for-terraform-over-hashicorp-configuration-language-for-our-infrastructure?hsLang=en)

 In this blog post, the author breaks down the challenges with HCL, why CDKTF’s programming-language flexibility was a game-changer, and how it’s helping us build a more scalable, maintainable infrastructure.

[![](https://miro.medium.com/v2/resize:fit:700/1*JpEcT3Ugg3cBEaDeCXan8A.jpeg)](https://insights.andamp.io/blog/extending-synpress-with-additional-metamask-commands?hsLang=en)

### [Extending Synpress with additional MetaMask commands](https://insights.andamp.io/blog/extending-synpress-with-additional-metamask-commands?hsLang=en)

 A guide on how to find and define new selectors for Puppeteer and add custom commands for Cypress to Synpress.

[![logo_white](https://27222727.fs1.hubspotusercontent-eu1.net/hubfs/27222727/logo_white.svg "logo_white")](http:/?hsLang=en)

[Follow &andamp on LinkedIn](https://www.linkedin.com/company/andamp/) [Follow &andamp on Instagram](https://www.instagram.com/_andamp_)

## Our Services

- [Team as a Service](https://insights.andamp.io/team-as-a-service/)

## Sitemap

- [Blog](https://insights.andamp.io/blog)
- [Career](https://insights.andamp.io/career)
- [About Us](https://insights.andamp.io/about-us)
- [Code of Conduct](https://insights.andamp.io/code-of-conduct)
- [Our Diversity Journey](https://andamp.io/diversity-journey)

## Our Mission

 We offer a risk-free way to optimize customer experience and realise your business' potential through MVPs

## Case Studies

- [Notarity](https://insights.andamp.io/case-studies/notarity/)

## Location

 andamp GmbH  
 Währinger Straße 48/2. Hof  
 1090 Vienna, Austria

## Contact Us

[hello@andamp.io](mailto:hello@andamp.io)  We would love to hear about your ideas!

### Let's build your project!

This site is protected by reCAPTCHA and the Google [Privacy Policy](https://policies.google.com/privacy) and [Terms of Service](https://policies.google.com/terms) apply.

® 2025 andamp GmbH [Legal Notice](https://insights.andamp.io/legal-notice/?hsLang=en) [Privacy Policy](https://insights.andamp.io/privacy-policy/?hsLang=en)

```json
{
  "@context" : "https://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Michael Jank",
    "url" : "https://insights.andamp.io/blog/author/michael-jank"
  },
  "dateModified" : "2023-05-24T10:37:47.048Z",
  "datePublished" : "2023-01-26T16:00:00.000Z",
  "headline" : "Testing MultiversX (former Elrond) Smart Contracts",
  "image" : [ "https://miro.medium.com/v2/resize:fit:1400/1*7QzI18A7wTLO92bwFm1_7w.png" ],
  "mainEntityOfPage" : {
    "@id" : "https://insights.andamp.io/blog/testing-multiversx-former-elrond-smart-contracts",
    "@type" : "WebPage"
  },
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "url" : "https://insights.andamp.io/hubfs/andamp%20Full%20Logo%20Blue%20Light.svg"
    },
    "name" : "andamp GmbH"
  }
}
```