Aptos Labs logo

Skill

move-test

generate unit tests for Move code

Covers Web3 Testing

Description

Generate unit tests for Move code. Use for test generation, writing tests, or improving coverage.

SKILL.md

Before doing any work, use TaskCreate to create one task for each **Task:** entry listed below. Then execute them in order, marking each in_progress when you start it and completed when you finish.

Test Generation Tasks — Execute In Order

Task: Check package. Build the package and establish a test coverage baseline. Fix any compilation errors or failing tests before proceeding.

Task: Analyze target code. Identify uncovered lines and testable behaviors (success paths, abort conditions, edge cases, potential bugs).

Task: Generate test module. Create tests in tests/move_flow/<module>_tests.move.

Task: Validate tests. Run tests. Fix compilation errors and wrong assertions. Move tests that expose real bugs to bugs/.

Task: Check coverage improvement. Verify new tests added coverage. Generate additional tests for remaining gaps if feasible.

Task: Minimize tests. Delete tests that add no new coverage. Keep distinct scenarios; prefer simpler setup and clearer naming.

Task: Report. Summarize tests generated, coverage achieved, and any potential bugs found.

The reference material below supports the tasks above.

Move Language

Move on Aptos is a safe, resource-oriented programming language for smart contracts on the Aptos blockchain. It uses a linear type system to enforce ownership and prevent double-spending at compile time.

Move Language Basics

  • Modules are the unit of code organization, published at an address.
  • Structs define data types; abilities (key, store, copy, drop) control what operations are permitted.
  • Entry functions (entry fun) are transaction entry points callable from outside Move.
  • View functions (#[view]) are read-only queries that do not modify state.
  • Global storage stores resources (structs with key) at addresses.
  • Move 2 syntax (required):
    • Read resource: &T[addr] (not borrow_global<T>(addr))
    • Mutate resource: &mut T[addr] (not borrow_global_mut<T>(addr))
    • Access field: T[addr].field directly (the compiler inserts the ref op)
    • acquires annotations are no longer needed — do not add them.
  • Error codes: Use named constants for abort codes (const E_NOT_FOUND: u64 = 1;) and document them.
  • Comments: Use // for regular comments. /// is a doc comment and is only valid directly before a module, struct, enum, fun, or const declaration.
  • Edit hook: The edit hook auto-runs on .move files after edits. If it reports compilation errors, fix them before proceeding with further changes.

Move Packages

A Move package is a directory with a Move.toml manifest and source files. The manifest defines the package name, dependencies, and named addresses.

Named Addresses

Modules are published at named addresses (e.g., @my_package). These must resolve to hex values for compilation.

  • [addresses] — production addresses (may use _ placeholder for deploy-time assignment)
  • [dev-addresses] — development/test values (used when compiling in dev or test mode)

Fixing "Unresolved addresses" errors: For each Named address 'X' in package 'Y', add X = "0x..." to [dev-addresses] in that package's Move.toml. Use 0x100 and up, avoiding reserved addresses (0x0=vm_reserved, 0x1=std/aptos_std/aptos_framework, 0x3=aptos_token, 0x4=aptos_token_objects, 0x5=aptos_trading, 0x7=aptos_experimental, 0xA=aptos_fungible_asset, 0xA550C18=core_resources):

[dev-addresses]
my_package = "0x100"
other_addr = "0x101"

Unit Test Generation Rules

Move Unit Testing Reference

Test Attributes

AttributeUsage
#[test]Marks a function as a test
#[test(name = @addr)]Test with signer parameters bound to addresses
#[test_only]Code only compiled for testing (modules, functions, structs, constants)
#[expected_failure]Test expected to abort (any code)
#[expected_failure(abort_code = N)]Expects abort with specific code
#[expected_failure(abort_code = N, location = mod)]Expects abort at specific location

Signer Parameters

Signers are bound via the test attribute, not passed as arguments:

// Single signer
#[test(account = @0x1)]
fun test_single(account: &signer) { }

// Multiple signers
#[test(admin = @admin_addr, user = @0x42)]
fun test_multi(admin: &signer, user: &signer) { }

// Framework signer for timestamp, account creation, etc.
#[test(aptos_framework = @aptos_framework)]
fun test_framework(aptos_framework: &signer) { }

Expected Failure

Use #[expected_failure] to test that code correctly aborts under certain conditions.

Basic usage (any abort passes):

#[test]
#[expected_failure]
fun test_will_abort() { abort 1 }

With abort code (must match exactly):

#[test]
#[expected_failure(abort_code = E_NOT_AUTHORIZED, location = Self)]
fun test_unauthorized() { /* should abort with E_NOT_AUTHORIZED */ }

With location (when error originates in another module):

#[test]
#[expected_failure(abort_code = 26113, location = extensions::table)]
fun test_table_error() { /* should abort in table module */ }

Execution errors (not abort, but runtime failures):

// Arithmetic error (overflow, divide by zero)
#[test]
#[expected_failure(arithmetic_error, location = Self)]
fun test_overflow() { let _ = 255u8 + 1; }

// Vector out of bounds
#[test]
#[expected_failure(vector_error, minor_status = 1, location = Self)]
fun test_out_of_bounds() { vector::borrow(&vector::empty<u8>(), 0); }

Test-Only Code

// Test-only module (entire module only compiled for tests)
#[test_only]
module my_addr::test_helpers {
    public fun setup(): u64 { 100 }
}

// Test-only function in regular module
module my_addr::my_module {
    #[test_only]
    public fun init_for_testing(account: &signer, value: u64) {
        move_to(account, MyResource { value });
    }
}

Useful Test Utilities

// Get address from signer
use std::signer;
let addr = signer::address_of(account);

// Create account (registers on-chain)
use aptos_framework::account;
account::create_account_for_test(addr);

// Create signer without registering (lightweight)
let signer = account::create_signer_for_test(@0x123);

// Check resource exists
assert!(exists<MyResource>(addr), E_NOT_FOUND);

// Initialize timestamp (required before time functions)
use aptos_framework::timestamp;
timestamp::set_time_has_started_for_testing(aptos_framework);

// Advance time
timestamp::update_global_time_for_test(1000000); // microseconds
timestamp::update_global_time_for_test_secs(100); // seconds

Test Design Rules

Design rules:

  • One behavior per test. Each test verifies exactly one scenario. Never combine success and failure cases.
  • Minimal setup. Only initialize what the specific test needs.
  • Test the target function. Every test must call the user-specified function.
  • Document purpose. Every test needs a comment explaining what behavior is tested.

Naming: test_<function>_<scenario> (e.g., test_transfer_insufficient_balance), module: <module>_tests

Common Mistakes:

  • RESOURCE_ALREADY_EXISTS: Don't initialize the same resource twice
  • MISSING_DATA: Ensure required resources exist before calling
  • Signer mismatch: Operations checking signer::address_of() require the correct signer. Match signers to expected addresses in test attributes.

Unit Test Generation — Detailed Instructions

Task: 1 — Check Package

  1. Call move_package_manifest to build the package and discover sources. Fix any compilation errors before proceeding.
  2. Call move_package_test with establish_baseline set to true. Fix failing tests before proceeding.

Task: 2 — Analyze Target Code

Specific function requested:

  1. Call move_package_coverage with function set to "module_name::function_name" — get uncovered lines in that function
  2. Read the source and identify behaviors to test:
    • Success path with valid inputs
    • Each distinct abort condition
    • Edge cases (empty, zero, boundaries)
    • Potential bugs

Full module mode:

  1. Call move_package_coverage — get uncovered lines per source file
  2. Read the source files that contain uncovered lines
  3. Identify testable functions: public, entry, public(friend) — skip #[test_only] and private
  4. For functions with uncovered lines, identify behaviors to test (same as above)

Task: 3 — Generate Test Module

Create tests/move_flow/<module>_tests.move (create directory if needed).

// =============================================================================
// AUTO-GENERATED TESTS - DO NOT EDIT MANUALLY
// Generated by: move-test agent
// Source module: <module>
// =============================================================================

#[test_only]
module <package_address>::<module>_tests {
    use <package_address>::<module>;

    #[test(account = @0x1)]
    /// @ai-generated
    /// Verifies that <function> <behavior>.
    fun test_<function>_<scenario>(account: &signer) { ... }
}

Full module mode: Generate tests in batches, one module at a time.

Suspected bugs: Assert the correct expected behavior — the test should fail against the buggy code.

Task: 4 — Validate Tests

Call move_package_test. If success is false, classify each failure:

  • Compilation error: Fix the test
  • Runtime failure: Compare test expectation against expected behavior
    • Test is wrong → Fix it
    • Code is wrong → Move test to bugs/ (at package root, next to sources/ and tests/) and document:
      • Expected behavior
      • Actual behavior
      • Why this indicates a bug

Iterate until all tests in tests/move_flow/ pass.

Task: 5 — Check Coverage Improvement

Check newly_covered from the validation step to confirm the generated tests added coverage. Use move_package_coverage to check remaining gaps (pass function as "module_name::function_name" when targeting a specific function) — generate additional tests if needed and feasible.

Task: 6 — Minimize Tests (do not skip)

Delete tests that add no new coverage. Keep tests with distinct scenarios (different abort conditions, branches, edge cases). When duplicates exist, prefer simpler setup and clearer naming.

Only modify tests in tests/move_flow/ — do not touch sources/ or tests/ root.

Task: 7 — Report

Summarize:

  • Tests generated and coverage achieved
  • If any tests were moved to bugs/, alert the user with a summary of potential bugs found

Task

Generate unit tests for the current Move package.

© 2026 YourAI.tools. Every skill from an identity-verified publisher.

Independent catalog. Not affiliated with, endorsed by, or sponsored by Anthropic or any listed publisher. All trademarks belong to their respective owners.