# Testing Guide

## Testing with Truffle <a href="#testing-with-truffle" id="testing-with-truffle"></a>

Truffle provides an automated testing framework. This framework lets you write simple and manageable tests in two different ways:

* In `Javascript` and `TypeScript`, for exercising your contracts from the outside world, just like application.
* In `Solidity`, for exercising your contracts in advances, bare-to-the-metal scenarios.

### 1) Get Started

Add a setter function `setGreet` to the contract for testing purpose. The source code is given below.

```solidity
pragma solidity ^0.5.6;
contract Mortal {
    /* Define variable owner of the type address */
    address payable owner;
    /* This function is executed at initialization and sets the owner of the contract */
    constructor () public { owner = msg.sender; }
    /* Function to recover the funds on the contract */
    function kill() public payable { if (msg.sender == owner) selfdestruct(owner); }
}

contract MEVerseGreeter is Mortal {
    /* Define variable greeting of the type string */
    string greeting;
    /* This runs when the contract is executed */
    constructor (string memory _greeting) public {
        greeting = _greeting;
    }
    /* Main function */
    function greet() public view returns (string memory) {
        return greeting;
    }

    /* Newly added function for testing. */
    function setGreet(string memory _greeting) public {
        // only owner can change greeting message
        require(msg.sender == owner, "Only owner is allowed.");
        greeting = _greeting;
    }
}
```

**Test Scenario**&#x20;

1. Whether `greet()` function returns  "Hello, MEVerse" properly
2. Whether `setGreet()` function returns new greeting message properly and reverts when non-owner account attempts to update the greeting.

First, we will install the Chai assertions library (or any different assertions library you use) for generic assertions, and the truffle-assertions library for the smart contract assertions.

```shell
npm install --save-dev chai truffle-assertions
```

### 2) Writing test in Solidity <a href="#id-2-writing-test-in-solidity" id="id-2-writing-test-in-solidity"></a>

Testing with Solidity can be a little bit more intuitive than JavaScript tests. Solidity test contracts live alongside JavaScript tests as .sol files.

Create a file called `TestMEVerseGreeting.sol`  in the `test` folder. The Truffle suite provides helper libraries for testing, so let's take a look at the example Solidity test:

```solidity
pragma solidity ^0.5.6;

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/HashMarket.sol";
```

* DeployedAddresses : Every time you change your contract, you must redeploy it to a new address. You can get the deployed contract addresses through this library.
* Assert : It gives us access to various testing functions, like `Assert.equals()`, `Assert.greaterThan()`, etc.

```solidity
pragma solidity ^0.5.6;

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/MEVerseGreeter.sol";

contract TestMEVerseGreeting {

    function testGreetingMessage() public {
        // DeployedAddresses.MEVerseGreeter() handles contract address.
        MEVerseGreeter greeter = MEVerseGreeter(DeployedAddresses.MEVerseGreeter());

        string memory expectedGreet = "Hello MEVerse";

        string memory greet = greeter.greet();

        Assert.equal(greet, expectedGreet, "greeting message should match");
    }
}
```

Run Solidity test code

```shell
$ truffle test
Using network 'test'.


Compiling your contracts...
===========================
> Compiling ./test/TestMEVerseGreeting.sol
> Artifacts written to /var/folders/8k/pj9b6lld4qn4hq1l7h97y9pm0000gn/T/test--5158-mS50YzRSpyUZ
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang



  TestMEVerseGreeting
    1) testGreetingMessage
    > No events were emitted


  0 passing (3s)
  1 failing

  1) TestMEVerseGreeting
       testGreetingMessage:
     Error: greeting message should match (Tested: Hello, MEVerse, Against: Hello MEVerse)
      at checkResultForFailure (/Users/meverselabs/.nvm/versions/node/v16.16.0/lib/node_modules/truffle/build/webpack:/packages/core/lib/testing/SolidityTest.js:66:1)
      at runMicrotasks (<anonymous>)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)
      at Context.<anonymous> (/Users/meverselabs/.nvm/versions/node/v16.16.0/lib/node_modules/truffle/build/webpack:/packages/core/lib/testing/SolidityTest.js:92:1)
```

It failed. Let's take a look at the error message.

`Error: greeting message should match (Tested: Hello, MEVerse, Against: Hello MEVerse)`

Notice the missed `',(comma)'` at *string memory expectedGreet = "Hello MEVerse"*.\
Fix the code and run the test again.

<pre class="language-shell"><code class="lang-shell"><strong>$ truffle test
</strong>Using network 'test'.


Compiling your contracts...
===========================
> Compiling ./test/TestMEVerseGreeting.sol
> Artifacts written to /var/folders/8k/pj9b6lld4qn4hq1l7h97y9pm0000gn/T/test--5231-DBNS4Mgo7Mo0
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang



  TestMEVerseGreeting
    ✓ testGreetingMessage (41ms)


  1 passing (3s)
</code></pre>

Test success!

If you want to test your contract on Testnet, use `network` option.

```shell
$ truffle test -network MEVerseTestnet
Using network 'test'.


Compiling your contracts...
===========================
> Compiling ./contracts/MEVerseGreeter.sol
> Compiling ./test/TestMEVerseGreeting.sol
> Artifacts written to /var/folders/8k/pj9b6lld4qn4hq1l7h97y9pm0000gn/T/test--5324-jtF8M5Qz82cV
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang



  TestMEVerseGreeting
    ✓ testGreetingMessage (55ms)


  1 passing (3s)
```

### 3) Writing test in JavaScript <a href="#id-3-writing-test-in-javascript" id="id-3-writing-test-in-javascript"></a>

Truffle uses the [Mocha](https://mochajs.org/) testing framework and [Chai](https://www.chaijs.com/) assertion library to provide a solid framework for JavaScript test. JavaScript test gives you more flexibility and enables you to write more complex tests.

Let's create a file and name it `0_MEVerseGreeting.js` under `test` directory.\
The test code is:

```javascript
// Interacting directly with MEVerseGreeter contract
const MEVerseGreeter = artifacts.require("./MEVerseGreeter.sol");
const truffleAssert = require('truffle-assertions');

contract("MEVerseGreeter", async(accounts) => {
    // store the contract instance at a higher level 
    // to enable access from all functions.
    var MEVerseGreeterInstance;
    var owner = accounts[0];
    var greetMsg = "Hello, MEVerse";

    // This will run before each test proceed.
    before(async function() {
        // set contract instance into a variable
        MEVerseGreeterInstance = await MEVerseGreeter.new(greetMsg, {from:owner});
    })

    it("#1 check Greeting message", async function() {
        // set the expected greeting message
        var expectedGreeting = greetMsg;
        var greet= await MEVerseGreeterInstance.greet();
        assert.equal(expectedGreeting, greet, "greeting message should match");

    })

    it("#2 update greeting message.", async function() {
        var newGreeting = "Hi, MEVerse";

        await MEVerseGreeterInstance.setGreet(newGreeting, { from:owner });
        var greet = await MEVerseGreeterInstance.greet();
        assert.equal(newGreeting, greet, "greeting message should match");
    });

    it("#3 [Failure test] Only owner can change greeting.", async function() {
        var fakeOwner = accounts[1];        
        await truffleAssert.fails(MEVerseGreeterInstance.setGreet(greetMsg, { from:fakeOwner }));
    });
});
```

Run test file `0_MEVerseGreeting.js`)

<pre class="language-shell"><code class="lang-shell"><strong>$ truffle test ./test/0_MEVerseGreeting.js
</strong>Using network 'test'.


Compiling your contracts...
===========================
> Compiling ./contracts/MEVerseGreeter.sol
> Artifacts written to /var/folders/8k/pj9b6lld4qn4hq1l7h97y9pm0000gn/T/test--5527-DYxpp0UInYnm
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang



  Contract: MEVerseGreeter
    ✓ #1 check Greeting message
    ✓ #2 update greeting message. (42ms)
    ✓ #3 [Failure test] Only owner can change greeting. (176ms)


  3 passing (301ms)
</code></pre>

For more details, please check [Truffle testing](https://www.trufflesuite.com/docs/truffle/testing/testing-your-contracts) and [Truffle commands](https://www.trufflesuite.com/docs/truffle/reference/truffle-commands#test) for details.
