example 仓库中的 counter 模块示例,而不是最小化的 counter 模块示例。
本页中的示例来自 完整 Counter 模块演练 和 运行与测试 教程。
三个测试层级
Keeper 单元测试
Keeper 单元测试会在不启动完整应用程序的情况下,隔离验证 keeper 逻辑。它们会构造一个最小的内存上下文,配合真实的 KV store,初始化待测 keeper,并直接调用其方法。不需要服务器、不需要网络,也不需要区块处理。 counter 模块的 keeper 测试位于x/counter/keeper/keeper_test.go。测试套件会创建一个带有真实 store 和 mock 依赖的 keeper:
testutil.DefaultContextWithDB 会创建一个由内存数据库支持的真实 KV store。moduletestutil.MakeTestEncodingConfig 会返回一个为测试配置好的 codec。MockBankKeeper 会替换真实的 bank keeper,使用一个其行为可按测试用例控制的结构体:
msg_server_test.go 使用同一个测试套件来测试 MsgServer 层,包括事件发出:
集成测试
集成测试会验证整个应用栈上的行为。它们会启动一个真实的内存网络,包含一个或多个验证者,等待区块产出,通过 gRPC 广播真实签名交易,并查询最终状态。这些测试会一并覆盖 AnteHandler、消息路由、区块执行和状态提交。 counter 模块的集成测试位于tests/counter_test.go。测试套件使用 Cosmos SDK 的 testutil/network 启动一条完整的内存链:
NewTestNetworkFixture(位于 tests/test_helpers.go)会使用 dbm.NewMemDB() 构造 ExampleApp,并返回一个用于配置内存验证者的 network.TestFixture。这样 SDK 的网络测试辅助工具就可以启动一个带有真实共识的真实应用。
一个覆盖完整交易路径的测试:
模拟测试
模拟测试是基于性质的测试。它们不是测试特定输入,而是生成大量随机操作,并验证应用程序的不变量在整个过程中始终成立。它们能够发现确定性测试用例遗漏的缺陷:意外的顺序效应、高负载下的状态损坏,以及只有在大量连续操作后才会出现的不变量违规。 Cosmos SDK 通过simsx 提供这一能力。counter 模块定义了一个消息工厂,用来生成随机的 MsgAddRequest 消息:
sim_test.go 中的顶层模拟测试会将这些部分连接起来:
//go:build sims 构建标签意味着模拟测试不会包含在常规的 go test 运行中,只有在显式传入 -tags sims 时才会执行。这样可以保持 CI 足够快速。
模拟管理器会在 app.go 中初始化:
NewSimulationManagerFromAppModules 会收集所有实现了 AppModuleSimulation 的模块所提供的模拟支持。RegisterStoreDecoders 会为每个模块的 store 条目注册可读的解码器,供模拟框架在记录状态以便调试时使用。
测试工具
testutil
testutil 包提供了用于为单元测试构造内存上下文的辅助工具:
testutil.DefaultContextWithDB会创建一个由内存 KV store 支持的真实sdk.Context。Keeper 单元测试使用它来获得一个真实的执行上下文,而无需启动完整节点。moduletestutil.MakeTestEncodingConfig会返回一个带有标准接口注册的 codec,适用于 keeper 测试。baseapp.NewQueryServerTestHelper会创建一个QueryServiceTestHelper,它同时实现 gRPC Server 和 ClientConn 接口,使 keeper 测试能够注册查询服务并直接调用它们,而无需网络连接。
testify suite
SDK 的测试文件使用testify/suite 包。suite.Suite 会将测试初始化、清理以及测试方法组织到同一个结构体中。SetupTest 会在每个测试方法之前运行;SetupSuite 会在该 suite 中的所有测试开始前仅运行一次。
suite.Run 会发现结构体上名称以 Test 开头的方法,并将它们作为独立测试用例运行。s.Require() 会返回断言辅助方法,在断言失败时立即停止测试;而 s.Assert() 会在失败后继续执行。
simsx 和 simd
关于如何配置和运行模拟测试的完整指南,请参阅模块模拟测试页面。simsx 是模拟执行框架。它提供:
SimMsgFactoryFn:一种函数类型,为消息工厂实现SimMsgFactoryX接口。每个工厂都会随机选择账户和参数,构造一条消息,并返回它以供执行。ChainDataSource:在构造消息期间提供对随机账户、余额以及其他链上数据的访问。SimulationReporter:允许工厂发出应跳过自身的信号(例如不存在合适账户时)。simsx.Run:顶层入口,用于驱动针对应用程序的一次完整模拟运行。
simd 是 Cosmos SDK 提供的参考模拟二进制。它是一个已完整配置的 simapp(simapp),并编译为独立二进制文件,用于在无需搭建自定义链的情况下,针对 SDK 自身的模块集运行模拟测试。对于示例应用这类自定义链,你需要使用带有 sims 构建标签的自有二进制。要了解如何运行示例链,请参阅 simd 节点教程。
要针对示例应用运行模拟测试:
AppModuleSimulation、编写消息工厂以及接入 SimulationManager,请参阅模块模拟测试。
Telemetry
counter 模块使用 OpenTelemetry 从 keeper 操作中发出指标:The Cosmos SDK provides a layered testing approach that mirrors the architecture of the framework itself. Tests are organized into three levels, each testing a progressively larger slice of the application. This page uses the counter module example in the
example repo, not the minimal counter module example, because the fuller module includes the testing surfaces needed for these examples.
The examples on this page come from the Full Counter Module Walkthrough and Running and Testing tutorials.
Three testing levels
Keeper unit tests
Keeper unit tests verify keeper logic in isolation, without starting a full application. They construct a minimal in-memory context with a real KV store, initialize the keeper under test, and call its methods directly. No server, no network, no block processing. The counter module keeper tests live inx/counter/keeper/keeper_test.go. The test suite sets up a keeper with a live store and mock dependencies:
testutil.DefaultContextWithDB creates a real KV store backed by an in-memory database. moduletestutil.MakeTestEncodingConfig returns a codec configured for the test. The MockBankKeeper replaces the real bank keeper with a struct whose behavior can be controlled per test case:
msg_server_test.go uses the same suite to test the MsgServer layer, including event emission:
Integration tests
Integration tests verify behavior across the full application stack. They start a real in-memory network with one or more validators, wait for blocks to be produced, broadcast actual signed transactions via gRPC, and query the resulting state. These tests exercise the AnteHandler, message routing, block execution, and state commitment together. The counter module integration tests live intests/counter_test.go. The test suite uses testutil/network from the Cosmos SDK to spin up a full in-memory chain:
NewTestNetworkFixture (in tests/test_helpers.go) constructs the ExampleApp with dbm.NewMemDB() and returns a network.TestFixture that configures the in-memory validator. This lets the SDK’s network test helper start a real application with real consensus.
A test that exercises the full transaction path:
Simulation tests
Simulation tests are property-based tests. Instead of testing specific inputs, they generate large volumes of random operations and verify that the application’s invariants hold throughout. They catch bugs that deterministic test cases miss: unexpected ordering effects, state corruption under high load, and invariant violations that only appear after many sequential operations. The Cosmos SDK simulation framework drives this throughsimsx. The counter module defines a message factory that generates random MsgAddRequest messages:
sim_test.go wires everything together:
//go:build sims build tag means simulation tests are excluded from regular go test runs and only execute when explicitly requested with -tags sims. This keeps CI fast.
The simulation manager is initialized in app.go:
NewSimulationManagerFromAppModules collects simulation support from all modules that implement AppModuleSimulation. RegisterStoreDecoders registers human-readable decoders for each module’s store entries, used when the simulation framework logs state for debugging.
Test utilities
testutil
Thetestutil package provides helpers for constructing in-memory contexts for unit tests:
testutil.DefaultContextWithDBcreates a realsdk.Contextbacked by an in-memory KV store. Keeper unit tests use this to get a realistic execution context without starting a full node.moduletestutil.MakeTestEncodingConfigreturns a codec with standard interface registration, suitable for keeper tests.baseapp.NewQueryServerTestHelpercreates aQueryServiceTestHelperthat implements both the gRPC Server and ClientConn interfaces, allowing keeper tests to register query services and invoke them directly without a network connection.
testify suite
The SDK’s test files use thetestify/suite package. A suite.Suite groups test setup, teardown, and test methods into a single struct. SetupTest runs before each test method; SetupSuite runs once before all tests in the suite.
suite.Run discovers methods on the struct whose names start with Test and runs them as individual test cases. s.Require() returns assertion helpers that stop the test immediately on failure, while s.Assert() continues after a failure.
simsx and simd
For a full guide on configuring and running simulations, see the Module Simulation page.simsx is the simulation execution framework. It provides:
SimMsgFactoryFn: a function type that implements theSimMsgFactoryXinterface for message factories. Each factory selects random accounts and parameters, constructs a message, and returns it for execution.ChainDataSource: provides access to random accounts, balances, and other chain data during message construction.SimulationReporter: allows a factory to signal that it should be skipped (for example, if no suitable account exists).simsx.Run: the top-level entry point that drives a full simulation run against the application.
simd is the reference simulation binary provided by the Cosmos SDK. It is a fully configured simapp (simapp) compiled as a standalone binary, used to run simulations against the SDK’s own module set without setting up a custom chain. For a custom chain like the example app, you use your own binary with the sims build tag. To learn how to run an example chain, visit the simd node tutorial.
To run simulations against the example app:
AppModuleSimulation, writing message factories, and wiring the SimulationManager — see Module Simulation.