Acton
Tutorial

Writing your first unit test in Tolk

Learn how to write unit tests in Tolk that test individual functions in isolation without contract deployment

In this article, we'll explore how to write unit tests in Tolk. Unit tests focus on testing individual functions in isolation, without involving contract deployment or message sending.

If you've written tests in TypeScript for smart contracts, you know that unit testing individual functions is challenging because you need to somehow expose the function being tested to call it from a TypeScript test.

Writing unit tests in Tolk frees you from these problems.

Let's write our first unit test in Tolk.

1. Tolk Test Structure

All test files have the .test.tolk extension, for example, wallet.test.tolk, which allows you to quickly identify test files among others. To create a new test, write getter methods with names starting with test .

The simplest unit test looks like this:

unit.test.tolk
import "@acton/testing/expect"

get fun `test unit`() {
    expect(5 + 5).toEqual(10);
}

Test functions must be getter methods (using get fun) and their names must be test xxx, otherwise the test runner will just ignore them.

Unit tests use an API very similar to what is used in TypeScript. expect() creates a matcher object with the passed value, toEqual() is one of the matcher methods that compares two values for equality. The standard library provides a full range of necessary matchers for different types. Moreover, creating your own matchers is trivial—we'll look at this further.

Now that we've written our first unit test, let's run it with the command:

acton test unit.test.tolk

The test should complete successfully.

2. Extending expect()

The Problem with Standalone Check Functions

Imagine you have some validation logic that you want to extract into a function. By extracting it into a function, you'll get code like this:

import "@acton/testing/expect"

fun checkIfValueIsEqualWithFlags(left: int, right: int, param1: bool, param2: bool) { ... }

get fun `test unit`() {
    checkIfValueIsEqualWithFlags(5 + 5, 10, false, true);
    expect(2 + 2).toEqual(1 + 3);
}

This approach works, but it breaks the fluent API pattern and makes tests harder to read.

The Solution: Custom Matchers

This code can be written much more readably and consistently by creating a custom matcher:

import "@acton/testing/expect"

fun Expectation<int>.toEqualWithFlags(self, right: int, param1: bool, param2: bool) { ... }

get fun `test unit`() {
    expect(5 + 5).toEqualWithFlags(10, false, true);
    expect(2 + 2).toEqual(1 + 3);
}

As you can see, instead of a standalone function, we added a new method directly to the type that expect() returns. Now using your matcher is no different from standard ones.

Custom matchers are a powerful way to create reusable validation logic. They keep your tests clean and focused on the business logic rather than implementation details.

Read the complete guide to custom matchers for detailed examples and best practices.

Summary

Congratulations! You've learned the fundamentals of unit testing in Tolk.

What we've covered:

  1. Setting up unit test files with the .test.tolk extension
  2. Writing basic test functions using getter methods
  3. Using the expect() API with built-in matchers like toEqual()
  4. Running tests with the acton test command
  5. Creating custom matchers by extending the Expectation type

Key takeaways:

  • Unit tests in Tolk use familiar JavaScript testing patterns
  • The expect() API supports chaining with various matchers
  • Custom matchers help keep complex validation logic reusable
  • Test files are easily identifiable with the .test.tolk suffix
  • Tests run with the simple acton test command

Next steps:

  • Try writing unit tests for your own utility functions
  • Create custom matchers for domain-specific validations
  • Read the complete guide to custom matchers for advanced patterns
  • Explore the full range of built-in matchers in the standard library

In the next article, we'll look at how integration tests are written, where we test real contract interactions!

Last updated on

On this page