Remove action Subpackage for Consistent Testing (2026-02-09)
Intent
The repository previously included a custom testing abstraction under x/nutil/testutil/action. This abstraction defined an Action interface and a Given / When / Then style test composition mechanism.
This pattern is no longer aligned with current testing practices in the codebase. Most modules now rely on:
- Table-driven tests
testify suites
- Direct use of
testapp, testnetwork, and testutil/assertion
The goal of this change is to remove the action subpackage entirely and ensure all tests follow a consistent, idiomatic Go testing style. No test behavior should change. Only test structure and helpers are affected.
1. What the action subpackage does today
Location: x/nutil/testutil/action
This package defines a small domain-specific testing abstraction. Key components:
Account helpers (account.go)
- Funds accounts or modules via the
BankKeeper
- Internally mints from the inflation module and transfers funds
- Exposed as:
FundAccount(account, amount) Action
FundModule(module, amount) Action
Block and time helpers (block.go)
- Mutates block height and block time
- Optionally runs
EndBlock, Commit, and BeginBlock
- Exposed as
Action constructors such as:
IncreaseBlockNumberBy
IncreaseBlockTimeBy
SetBlockTime
MoveToNextBlock
- Variants that accept a duration or explicit timestamp
Test orchestration (testcase.go)
- Defines:
Action interface:
Do(app *NibiruApp, ctx sdk.Context) (sdk.Context, error)
TestCase with Given, When, and Then action lists
TestSuite that executes multiple test cases
- Each test case:
- Creates a fresh app and context
- Executes actions sequentially:
given → when → then
Conclusion
This abstraction is redundant. The same behavior already exists elsewhere in simpler and more idiomatic forms.
2. Inventory of remaining usage
Before removal, confirm whether the action subpackage is still used.
What to search for
- Imports of:
- Usage of:
action.TC(...)
.Given(...), .When(...), .Then(...)
- Any references to the
Action interface
Current state
As of this document:
- There are no remaining imports or call sites.
- A repository-wide search finds no usage outside the package itself.
- The
action subpackage is therefore dead code.
If future work uncovers usage, document it explicitly before proceeding, for example:
Remaining usage
path/to/file_test.go: uses action.TC for integration tests
3. Standard testing pattern going forward
Tests must not use the Action interface or TestCase abstraction.
Required building blocks
- App setup
- Use
x/nutil/testutil/testapp
- Use
x/nutil/testutil/testnetwork for multi-node tests
- Funding
- Use:
testapp.FundAccount
testapp.FundModuleAccount
- Assertions
- Use helpers from
x/nutil/testutil/assertion
- Structure
- Table-driven tests or
testify suites
- Explicit steps written directly in the test body
Guideline
If a test step cannot be expressed clearly as plain Go code, extract a small helper function. Do not reintroduce a DSL or test orchestration framework.
4. Replacement for helpers in action
Account funding
No changes required.
The following already exist and are equivalent:
testapp.FundAccount
testapp.FundModuleAccount
The action equivalents are redundant.
Block and time progression
The block progression logic in action/block.go is still useful, but it should be exposed as plain helper functions, not as Action implementations.
Required helpers
Extract the logic into regular functions, for example:
IncreaseBlockNumberBy(ctx sdk.Context, numBlocks int64) sdk.Context
IncreaseBlockTimeBy(ctx sdk.Context, delta time.Duration) sdk.Context
SetBlockTime(ctx sdk.Context, t time.Time) sdk.Context
SetBlockNumber(ctx sdk.Context, height int64) sdk.Context
MoveToNextBlock(app *NibiruApp, ctx sdk.Context) (sdk.Context, error)
Optional variants should only be added if they are actively needed.
Implementation rules
- Reuse the existing logic from
action/block.go
- Preserve behavior exactly:
- Same block lifecycle calls
- Same context creation semantics
- Place helpers in a clear location, such as:
x/nutil/testutil/block.go
- or another focused testutil file
TestCase and TestSuite
Do not preserve these abstractions.
If any usage is discovered later, rewrite tests using:
t.Run(...)
- Direct app and context setup
- Explicit sequencing of steps
5. Refactoring existing tests (if any are found)
If the inventory step reveals usage:
- Replace:
action.TC("name").
Given(...).
When(...).
Then(...)
with:
t.Run("name", func(t *testing.T) {
...
})
- Inline the test steps in order.
- Use
testapp and the new block helpers directly.
- Remove all
action imports.
- Keep behavior identical.
Refactor incrementally, one file at a time.
6. Remove the action package
Once no usage remains:
- Delete the directory:
- Run:
or the equivalent test command used by the repo.
7. Documentation updates
- Review
x/nutil/testutil/README.md
- Remove any references to the
action DSL if present
- Add a short example showing the preferred testing pattern
- Optionally add a brief note to contributor or testing guidelines stating that the
action DSL has been removed and should not be reintroduced.
8. Validation checklist
Before closing the issue, confirm:
Once complete, issue #2454 is resolved.
Remove
actionSubpackage for Consistent Testing (2026-02-09)Intent
The repository previously included a custom testing abstraction under
x/nutil/testutil/action. This abstraction defined anActioninterface and aGiven / When / Thenstyle test composition mechanism.This pattern is no longer aligned with current testing practices in the codebase. Most modules now rely on:
testifysuitestestapp,testnetwork, andtestutil/assertionThe goal of this change is to remove the
actionsubpackage entirely and ensure all tests follow a consistent, idiomatic Go testing style. No test behavior should change. Only test structure and helpers are affected.1. What the
actionsubpackage does todayLocation:
x/nutil/testutil/actionThis package defines a small domain-specific testing abstraction. Key components:
Account helpers (
account.go)BankKeeperFundAccount(account, amount) ActionFundModule(module, amount) ActionBlock and time helpers (
block.go)EndBlock,Commit, andBeginBlockActionconstructors such as:IncreaseBlockNumberByIncreaseBlockTimeBySetBlockTimeMoveToNextBlockTest orchestration (
testcase.go)Actioninterface:TestCasewithGiven,When, andThenaction listsTestSuitethat executes multiple test casesgiven → when → thenConclusion
This abstraction is redundant. The same behavior already exists elsewhere in simpler and more idiomatic forms.
2. Inventory of remaining usage
Before removal, confirm whether the
actionsubpackage is still used.What to search for
action.TC(...).Given(...),.When(...),.Then(...)ActioninterfaceCurrent state
As of this document:
actionsubpackage is therefore dead code.If future work uncovers usage, document it explicitly before proceeding, for example:
3. Standard testing pattern going forward
Tests must not use the
Actioninterface orTestCaseabstraction.Required building blocks
x/nutil/testutil/testappx/nutil/testutil/testnetworkfor multi-node teststestapp.FundAccounttestapp.FundModuleAccountx/nutil/testutil/assertiontestifysuitesGuideline
If a test step cannot be expressed clearly as plain Go code, extract a small helper function. Do not reintroduce a DSL or test orchestration framework.
4. Replacement for helpers in
actionAccount funding
No changes required.
The following already exist and are equivalent:
testapp.FundAccounttestapp.FundModuleAccountThe
actionequivalents are redundant.Block and time progression
The block progression logic in
action/block.gois still useful, but it should be exposed as plain helper functions, not asActionimplementations.Required helpers
Extract the logic into regular functions, for example:
IncreaseBlockNumberBy(ctx sdk.Context, numBlocks int64) sdk.ContextIncreaseBlockTimeBy(ctx sdk.Context, delta time.Duration) sdk.ContextSetBlockTime(ctx sdk.Context, t time.Time) sdk.ContextSetBlockNumber(ctx sdk.Context, height int64) sdk.ContextMoveToNextBlock(app *NibiruApp, ctx sdk.Context) (sdk.Context, error)Optional variants should only be added if they are actively needed.
Implementation rules
action/block.gox/nutil/testutil/block.goTestCase and TestSuite
Do not preserve these abstractions.
If any usage is discovered later, rewrite tests using:
t.Run(...)5. Refactoring existing tests (if any are found)
If the inventory step reveals usage:
testappand the new block helpers directly.actionimports.Refactor incrementally, one file at a time.
6. Remove the
actionpackageOnce no usage remains:
7. Documentation updates
x/nutil/testutil/README.mdactionDSL if presentactionDSL has been removed and should not be reintroduced.8. Validation checklist
Before closing the issue, confirm:
x/nutil/testutil/actionremainactiondirectory is fully deletedgo test ./x/nutil/...passesOnce complete, issue #2454 is resolved.