gnoset up. See Installation.
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.
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)
}
}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.
:::
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 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.
:::
// 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# 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 .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.
:::
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.