Skip to content

Latest commit

 

History

History
234 lines (170 loc) · 6.38 KB

File metadata and controls

234 lines (170 loc) · 6.38 KB

Running & Testing Gno code

Prerequisites

Overview

In this tutorial, you will learn how to run and test your Gno code locally, by using the gno binary. For this example, we will use the Counter code from a previous tutorial.

Setup

Start by creating a directory which will contain your Gno code:

mkdir counter
cd counter

Next, initialize a gnomod.toml file. This file declares the package path of your realm and the Gno language version, and is required by Gno tooling. You can do this using the following command:

gno mod init gno.land/r/<namespace>/counter

Replace <namespace> with your username. In this example, we’ll use example. This command creates a file with the following content:

module gno.land/r/example/counter

Then, in the same directory, create two files- counter.gno & counter_test.gno:

touch counter.gno counter_test.gno

Paste the code from the previous tutorial into these files.

counter.gno:

package counter

import "strconv"

var count int

func Increment(_ realm, change int) int {
	count += change
	return count
}

func Render(_ string) string {
	return "Current counter value: " + strconv.Itoa(count)
}

counter_test.gno:

package counter

import "testing"

func TestIncrement(t *testing.T) {
	// Check initial value
	if count != 0 {
		t.Fatalf("Expected 0, got %d", count)
	}

	// Call Increment
	value := Increment(cross, 42)

	// Check result
	if value != 42 {
		t.Fatalf("Expected 42, got %d", count)
	}
}

Testing

To run package tests, use the gno test subcommand and pass it the directory containing the tests. From inside the counter/ directory, run:

$ gno test .
ok      .       0.81s

To see a detailed list of tests that were executed, we can add the verbose flag:

$ gno test . -v
=== RUN   TestIncrement
--- PASS: TestIncrement (0.00s)
ok      .       0.81s

In addition to -v, other flags are available, such as options for setting test timeouts, checking performance metrics, and more.

:::info Mocked testing & running environment The gno binary mocks a blockchain environment when running & testing code. See Final remarks. :::

Running Gno code

The gno binary also provides a run subcommand, which allows you to evaluate specific expressions in your Gno code without starting a full blockchain environment. Internally, the Gno Virtual Machine (GnoVM) evaluates the given expression and returns its value, without making any permanent changes to contract storage.

This is a convenient way to quickly test or evaluate a function during development without spinning up a full blockchain.

By default, the GnoVM does not automatically print return values when evaluating expressions. For this reason, you need to include a println() call—either inside the function itself or directly in the evaluated expression:

gno run -expr "println(Increment(42))"

Try running this expression for yourself:

package counter

import "strconv"

var count int

func Increment(_ realm, change int) int {
	count += change
	return count
}

func Render(_ string) string {
	return "Current counter value: " + strconv.Itoa(count)
}

The run subcommand also supports a full GnoVM debugger, which can be started with the -debug flag. Read more about it here.

Filetests

Filetests are golden tests typically used to test realms. They execute a main function and compare actual output against expected output written as comment directives at the bottom of the file.

Filetests use the *_filetest.gno suffix and are placed in a filetests/ subdirectory of the realm package.

:::warning Stability notice Filetests are primarily intended as an internal tool. Their API and behavior are not guaranteed to be as stable as standard gno test testing. :::

Example

// PKGPATH: gno.land/r/demo/counter_test
// SEND: 1000000ugnot
package counter_test

import "gno.land/r/demo/counter"

func main() {
	counter.Increment(cross)
	println(counter.Render(""))
}

// Output:
// 1

Running filetests

# Only run the filetest for a package (from the package directory)
gno test -run "_filetest.gno" .
# Update expected values when output intentionally changes
gno test --update-golden-tests .

Directives

Input directives are single-line comments at the top of the file:

Directive Description Default
PKGPATH Package path. Use r/ for realms. main
MAXALLOC Max memory allocation in bytes. 0
SEND Coins sent with the transaction. (none)

Output directives are multi-line comments at the bottom:

Directive Matches
Output Standard output.
Error Panic or error message.
Realm Realm state change operations.
Events Emitted events (JSON).
Preprocessed Preprocessed AST.
Stacktrace Gno stacktrace on panic.
Gas Gas consumed.
Storage Realm storage size diff.
TypeCheckError Go type-checker error.

:::info Pure package imports Imports of pure packages are processed separately. If a pure package contains a line like println(1), its output cannot be checked by an // Output: directive. :::

Final remarks

Note that executing and testing code as shown in this tutorial utilizes a local, mocked execution environment. During testing and expression evaluation, the GnoVM is simply running as a language interpreter, with no connection to a real blockchain.

No real on-chain transactions occur, and the state changes are purely in-memory for testing and development purposes. You might notice this if you run the same expression modifying a state variable twice, with the actual value staying unchanged.

All imports used in your code are resolved from the GnoVM's installation directory.