Testing Solana Programs (Anchor) with Mocha
Published: 2024-04-17 10:03:22

# Introduction

Testing your programs is essential to ensure the reliability and functionality of your code and ensure it performs as intended. In this article, we will provide a comprehensive guide on writing tests using Mocha JS. We'll focus on a program developed by DataKnox in Anchor, a specialized Rust framework for Solana programs.

Here is what the program looks like:

```rust
use anchor_lang::prelude::*;

declare_id!("ByxaKZWC2QqigDuUjxH6nMv3MdVgBNzbpdRmiEE3ssn9");

#[program]
pub mod flipper {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let switchAccount = &mut ctx.accounts.switchAccount;
        switchAccount.state = true;
        Ok(())
    }

    pub fn flip(ctx: Context<Flip>) -> Result<()> {
        let switchAccount = &mut ctx.accounts.switchAccount;
        if switchAccount.state {
            switchAccount.state = false
        } else {
            switchAccount.state = true
        }
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = user, space = 16 + 16)]
    pub switchAccount: Account<'info, SwitchAccount>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Flip<'info> {
    #[account(mut)]
    pub switchAccount: Account<'info, SwitchAccount>,
} 

#[account]
pub struct SwitchAccount {
    pub state: bool,
}
```

The first step would be to run `anchor build` to compile the program and generate a keypair that can be used to deploy it.

We also need to get our program ID (an address for the program that our program can be identified with) using the command:

`solana address -k target/deploy/flipper-keypair.json`. Replace `flipper` with the name of your program.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1693464553997/cbe511a2-f193-45a6-b8de-a496cded7759.png align="center")

In our code, the program ID needs to go in two places:

* The `declare_id!` macro at the top of our program’s source code.
    
* The `Anchor.toml` file under the key with the same name as your program.
    

```rust
declare_id!("ByxaKZWC2QqigDuUjxH6nMv3MdVgBNzbpdRmiEE3ssn9");
```

```rust
[programs.localnet]
flipper = "ByxaKZWC2QqigDuUjxH6nMv3MdVgBNzbpdRmiEE3ssn9"
```

# **Prerequisites**

Before we dive into testing, make sure you have the following prerequisites in place:

1. **Solana CLI**: Install the Solana Command Line Interface (CLI) tools by following the instructions [**here**](https://docs.solana.com/cli/install-solana-cli-tools).
    
2. **Node.js and NPM**: Ensure you have Node.js and NPM installed on your system. You can download them from [**nodejs.org**](http://nodejs.org).
    

# **Setting our Solana Environment**

This process involves using a local Solana validator to simulate the Solana blockchain network using the Solana CLI to provide practical insights into the program's behavior.

### Generate a Keypair:

We start by generating a key pair for the dev environment by using the command `solana-keygen new` and you will get an address that you can use to interact with the blockchain.

### **Configure RPC-URL:**

For our local testing, we need to set the RPC-URL to [localhost](http://localhost) using the command: `solana config set --url` [`localhost`](http://localhost).

The output should look like this:

![](https://lh5.googleusercontent.com/pJ0aZOMGzs_zNfd-yswDAjMzkCNryW1Q10cdLK2912cLAtzCvy61WhOEkTlDykDc-4-VqqSBu5QWXvlZbpe9RfK9OVV_O1iL2pCpWFc9uqXch1hKNTL2oUQlNjcnu6mmNr3BPKrb-rOckjLktVnEl20 align="left")

### **Start the Test Validator**

The next step would be to start our test validator using the command `solana-test-validator`. This would help simulate the Solana blockchain locally.

With our test validator running, we can now make requests (like request airdrop, get details about our address, deploy and test our program) to our local blockchain.

### Deploy to Localhost

With `solana-test-validator` running on your local machine, you can deploy the contract with the command: `anchor deploy`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1693494662866/2330167f-cec4-4ac7-834a-360e680e570d.png align="center")

# **Writing the Test in Mocha**

When the `anchor build` command is executed, Anchor automatically generates a test file for us, complete with a basic scaffold for the code. The test is written in Mocha, the `it` functions are used for the individual tests, and the `describe` function helps organize and group related tests together.

```javascript
//Import necessary libraries
const anchor = require("@coral-xyz/anchor");
const assert = require("assert");
const { SystemProgram } = anchor.web3;

// Set up Mocha test suite
describe("flipper", () => {
  // Configure the client to use the local cluster.
  const provider = anchor.AnchorProvider.env();
  anchor.setProvider(provider);
  const program = anchor.workspace.Flipper;
});
```

We then have two tests for each of our instructions from the `flipper` program.

### Testing the Initialize Instruction

The first test calls the `initialize` instruction of the flipper program, then fetches the account data and checks if the property of the account is true.

```javascript
it("Creates and Flip Account", async () => {
    // Generate a keypair
    const switchAccount = anchor.web3.Keypair.generate();
    // Call the initialize function
    await program.methods
      .initialize()
      .accounts({
        switchAccount: switchAccount.publicKey,
        user: provider.wallet.publicKey,
        systemProgram: SystemProgram.programId,
      })
      .signers([switchAccount])
      .rpc();
    // Fetch account data
    const baseAccount = await program.account.switchAccount.fetch(
      switchAccount.publicKey
    );
    assert.ok(baseAccount.state);
    _baseAccount = baseAccount;
  });
```

### Testing the Flip Instruction

The next test calls the `flip` instruction of the flipper program, specifying the `switchAccount` as the only account that is needed. Finally, it gets the `switchAccount` from the Solana cluster and asserts that its state is false.

```javascript
it("Flip It", async () => {
    const baseAccount = _baseAccount;
    // Call the flip function
    await program.methods
      .flip()
      .accounts({
        accounts: {
          dataAccount: baseAccount.publicKey,
        },
      })
      .rpc();
    // Fetch the account data
    const account = await program.account.dataAccount.fetch(
      baseAccount.publicKey
    );
    assert.ok(account.state == false);
  });
```

### Running the Tests

You can run the tests for your Solana program using the following command:

`anchor test`

This command will execute your Mocha tests and provide feedback on the program's behavior.

# Conclusion

Overall, testing is an essential part of the software development. Testing programs can help to ensure that our codes are of the highest quality and that they meet the intended needs.

To delve deeper into the Solana ecosystem or embark on your journey of building on Solana, the [**Solana Dev Resource**](https://solana.com/developers) is an excellent starting point.