-
Notifications
You must be signed in to change notification settings - Fork 23
Getting Started with Unit Tests
- .NET Core SDK (>2.1.4)
An already setup project can be pulled in with a couple quick commands. Open command line / terminal and run the following commands inside a empty directory for your project.
dotnet new --install Meadow.ProjectTemplate
dotnet new meadow
Skip down to Run Tests or continue to the next step to setup a project from scratch.
Open command line / terminal and create a new C# project with the command dotnet new console --name YOUR_PROJECT_NAME
Example:
dotnet new console --name MyProject
Add the Meadow unit testing framework package with the command dotnet add package Meadow.UnitTestTemplate
cd MyProject
dotnet add package Meadow.UnitTestTemplate
Create a directory named contracts
to place your Solidity source files (the directory must be named contracts
).
mkdir contracts
Add your Solidity source files to the contracts
directory.
Here's an example hello world Solidity contract that we'll save to our contracts
directory as HelloWorld.sol
. Solidity source files must have the .sol
file extension.
pragma solidity ^0.4.24;
contract HelloWorld {
event HelloEvent(string _message, address _sender);
function renderHelloWorld () public returns (string) {
emit HelloEvent("Hello world", msg.sender);
return "Hello world";
}
}
Run dotnet build
and you should see a GeneratedContracts
directory with generated source files matching your Solidity contracts. In our example we'll have a GeneratedContracts/HelloWorld.sol.cs
.
Create a .cs
file in your project directory to add our contract test code. For example HelloWorldTests.cs
.
Create a test class. The following example will deploy our contract, test a function call result, and test a transaction execution and validate its event log.
using Meadow.Contract;
using Meadow.JsonRpc.Types;
using Meadow.UnitTestTemplate;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading.Tasks;
namespace MyProject
{
// Inherit from 'ContractTest' to be provided with an RpcClient,
// Accounts, and several other useful features.
[TestClass]
public class HelloWorldTests : ContractTest
{
HelloWorld _contract;
// This triggers the coverage report generation (only needed once in the project).
[AssemblyCleanup]
public static async Task Cleanup()
{
await Global.GenerateCoverageReport();
}
// Method is ran before each test (all tests are ran in isolation).
// This is an appropriate area to do contract deployment.
protected override async Task BeforeEach()
{
// Deploy our test contract
_contract = await HelloWorld.New(RpcClient);
}
[TestMethod]
public async Task ValidateCallResult()
{
// Call the renderHelloWorld function and get the return value.
var callResult = await _contract.renderHelloWorld().Call();
// Validate the return value is what we expect.
Assert.AreEqual("Hello world", callResult);
}
[TestMethod]
public async Task ValidateTransactionEventResult()
{
// Execute the renderHelloWorld function as a transaction.
var txHash = await _contract.renderHelloWorld().SendTransaction();
// Get the transaction receipt.
var receipt = await RpcClient.GetTransactionReceipt(txHash);
// Get the event log from receipt that we are expecting.
var eventLog = receipt.FirstEventLog<HelloWorld.HelloEvent>();
// Optionally, the above steps can be shorted to..
eventLog = await _contract
.renderHelloWorld()
.FirstEventLog<HelloWorld.HelloEvent>();
// Validate the event log arg is what we expect.
Assert.AreEqual("Hello world", eventLog._message);
}
[TestMethod]
public async Task ValidateTransactionSender()
{
// An array of accounts is available as:
var fromAccount = Accounts[5];
// An RPC client instance is available, example:
var balance = await RpcClient.GetBalance(
fromAccount,
BlockParameterType.Latest);
// By default the first RPC account is used for calls and transactions.
// We can specify which account to use with TransactionParams..
var txParams = new TransactionParams { From = Accounts[5] };
var receipt = await _contract
.renderHelloWorld()
.TransactionReceipt(txParams);
// Validate the msg.sender as set in our example event log.
var eventLog = receipt.FirstEventLog<HelloWorld.HelloEvent>();
Assert.AreEqual(eventLog._sender, fromAccount);
}
}
}
Run the command dotnet test
in your project directory. If successful you should see:
Starting test execution, please wait...
Total tests: 3. Passed: 3. Failed: 0. Skipped: 0.
Test Run Successful.
If using VS Code you can use the Omnisharp C# extension to have inline test execution shortcuts. At the top of each TestClass
will be a Run All
shortcut that will run all tests within that class. Alternatively, each test can be run individually by using the Run Test
shortcut for any given test.
Running all tests
Running a single test
A Report
directory will be created in your project directory after the unit tests have run.
Open the Report/index.html
file in a web browser to see the Solidity code coverage report.