The Cosmos SDK contains different types of tests. These tests have different goals and are used at different stages of the development cycle. We advice, as a general rule, to use tests at all stages of the development cycle. It is adviced, as a chain developer, to test your application and modules in a similar way than the SDK. The rationale behind testing can be found in ADR-59.

Unit Tests

Unit tests are the lowest test category of the test pyramid. All packages and modules should have unit test coverage. Modules should have their dependencies mocked: this means mocking keepers. The SDK uses mockgen to generate mocks for keepers:
#!/usr/bin/env bash

mockgen_cmd="mockgen"
$mockgen_cmd -source=client/account_retriever.go -package mock -destination testutil/mock/account_retriever.go
$mockgen_cmd -package mock -destination testutil/mock/tendermint_tm_db_DB.go github.com/tendermint/tm-db DB
$mockgen_cmd -source=types/module/module.go -package mock -destination testutil/mock/types_module_module.go
$mockgen_cmd -source=types/module/mock_appmodule_test.go -package mock -destination testutil/mock/types_mock_appmodule.go
$mockgen_cmd -source=types/invariant.go -package mock -destination testutil/mock/types_invariant.go
$mockgen_cmd -package mock -destination testutil/mock/grpc_server.go github.com/cosmos/gogoproto/grpc Server
$mockgen_cmd -package mock -destination testutil/mock/tendermint_tendermint_libs_log_DB.go github.com/tendermint/tendermint/libs/log Logger
$mockgen_cmd -source=orm/model/ormtable/hooks.go -package ormmocks -destination orm/testing/ormmocks/hooks.go
$mockgen_cmd -source=x/nft/expected_keepers.go -package testutil -destination x/nft/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/feegrant/expected_keepers.go -package testutil -destination x/feegrant/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/mint/types/expected_keepers.go -package testutil -destination x/mint/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/params/proposal_handler_test.go -package testutil -destination x/params/testutil/staking_keeper_mock.go
$mockgen_cmd -source=x/crisis/types/expected_keepers.go -package testutil -destination x/crisis/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/auth/types/expected_keepers.go -package testutil -destination x/auth/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/auth/ante/expected_keepers.go -package testutil -destination x/auth/ante/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/authz/expected_keepers.go -package testutil -destination x/authz/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/bank/types/expected_keepers.go -package testutil -destination x/bank/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/group/testutil/expected_keepers.go -package testutil -destination x/group/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/evidence/types/expected_keepers.go -package testutil -destination x/evidence/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/distribution/types/expected_keepers.go -package testutil -destination x/distribution/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/slashing/types/expected_keepers.go -package testutil -destination x/slashing/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/genutil/types/expected_keepers.go -package testutil -destination x/genutil/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/gov/testutil/expected_keepers.go -package testutil -destination x/gov/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/staking/types/expected_keepers.go -package testutil -destination x/staking/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/auth/vesting/types/expected_keepers.go -package testutil -destination x/auth/vesting/testutil/expected_keepers_mocks.go
You can read more about mockgen here.

Example

As an example, we will walkthrough the keeper tests of the x/gov module. The x/gov module has a Keeper type requires a few external dependencies (ie. imports outside x/gov to work properly).
package keeper

import (
    
	"fmt"
    "time"
    "github.com/tendermint/tendermint/libs/log"
    "github.com/cosmos/cosmos-sdk/baseapp"
    "github.com/cosmos/cosmos-sdk/codec"
	storetypes "github.com/cosmos/cosmos-sdk/store/types"
	sdk "github.com/cosmos/cosmos-sdk/types"
	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    "github.com/cosmos/cosmos-sdk/x/gov/types"
	v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
    "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
)

/ Keeper defines the governance module Keeper
type Keeper struct {
    authKeeper types.AccountKeeper
	bankKeeper types.BankKeeper

	/ The reference to the DelegationSet and ValidatorSet to get information about validators and delegators
	sk types.StakingKeeper

	/ GovHooks
	hooks types.GovHooks

	/ The (unexposed)

keys used to access the stores from the Context.
	storeKey storetypes.StoreKey

	/ The codec for binary encoding/decoding.
	cdc codec.BinaryCodec

	/ Legacy Proposal router
	legacyRouter v1beta1.Router

	/ Msg server router
	router *baseapp.MsgServiceRouter

	config types.Config

	/ the address capable of executing a MsgUpdateParams message. Typically, this
	/ should be the x/gov module account.
	authority string
}

/ GetAuthority returns the x/gov module's authority.
func (k Keeper)

GetAuthority()

string {
    return k.authority
}

/ NewKeeper returns a governance keeper. It handles:
/ - submitting governance proposals
/ - depositing funds into proposals, and activating upon sufficient funds being deposited
/ - users voting on proposals, with weight proportional to stake in the system
/ - and tallying the result of the vote.
/
/ CONTRACT: the parameter Subspace must have the param key table already initialized
func NewKeeper(
	cdc codec.BinaryCodec, key storetypes.StoreKey, authKeeper types.AccountKeeper,
	bankKeeper types.BankKeeper, sk types.StakingKeeper,
	router *baseapp.MsgServiceRouter, config types.Config, authority string,
) *Keeper {
	/ ensure governance module account is set
    if addr := authKeeper.GetModuleAddress(types.ModuleName); addr == nil {
    panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
}
    if _, err := sdk.AccAddressFromBech32(authority); err != nil {
    panic(fmt.Sprintf("invalid authority address: %s", authority))
}

	/ If MaxMetadataLen not set by app developer, set to default value.
    if config.MaxMetadataLen == 0 {
    config.MaxMetadataLen = types.DefaultConfig().MaxMetadataLen
}

return &Keeper{
    storeKey:   key,
		authKeeper: authKeeper,
		bankKeeper: bankKeeper,
		sk:         sk,
		cdc:        cdc,
		router:     router,
		config:     config,
		authority:  authority,
}
}

/ Hooks gets the hooks for governance *Keeper {
    func (keeper *Keeper)

Hooks()

types.GovHooks {
    if keeper.hooks == nil {
		/ return a no-op implementation if no hooks are set
		return types.MultiGovHooks{
}
	
}

return keeper.hooks
}

/ SetHooks sets the hooks for governance
func (keeper *Keeper)

SetHooks(gh types.GovHooks) *Keeper {
    if keeper.hooks != nil {
    panic("cannot set governance hooks twice")
}

keeper.hooks = gh

	return keeper
}

/ SetLegacyRouter sets the legacy router for governance
func (keeper *Keeper)

SetLegacyRouter(router v1beta1.Router) {
	/ It is vital to seal the governance proposal router here as to not allow
	/ further handlers to be registered after the keeper is created since this
	/ could create invalid or non-deterministic behavior.
	router.Seal()

keeper.legacyRouter = router
}

/ Logger returns a module-specific logger.
func (keeper Keeper)

Logger(ctx sdk.Context)

log.Logger {
    return ctx.Logger().With("module", "x/"+types.ModuleName)
}

/ Router returns the gov keeper's router
func (keeper Keeper)

Router() *baseapp.MsgServiceRouter {
    return keeper.router
}

/ LegacyRouter returns the gov keeper's legacy router
func (keeper Keeper)

LegacyRouter()

v1beta1.Router {
    return keeper.legacyRouter
}

/ GetGovernanceAccount returns the governance ModuleAccount
func (keeper Keeper)

GetGovernanceAccount(ctx sdk.Context)

authtypes.ModuleAccountI {
    return keeper.authKeeper.GetModuleAccount(ctx, types.ModuleName)
}

/ ProposalQueues

/ InsertActiveProposalQueue inserts a proposalID into the active proposal queue at endTime
func (keeper Keeper)

InsertActiveProposalQueue(ctx sdk.Context, proposalID uint64, endTime time.Time) {
    store := ctx.KVStore(keeper.storeKey)
    bz := types.GetProposalIDBytes(proposalID)

store.Set(types.ActiveProposalQueueKey(proposalID, endTime), bz)
}

/ RemoveFromActiveProposalQueue removes a proposalID from the Active Proposal Queue
func (keeper Keeper)

RemoveFromActiveProposalQueue(ctx sdk.Context, proposalID uint64, endTime time.Time) {
    store := ctx.KVStore(keeper.storeKey)

store.Delete(types.ActiveProposalQueueKey(proposalID, endTime))
}

/ InsertInactiveProposalQueue inserts a proposalID into the inactive proposal queue at endTime
func (keeper Keeper)

InsertInactiveProposalQueue(ctx sdk.Context, proposalID uint64, endTime time.Time) {
    store := ctx.KVStore(keeper.storeKey)
    bz := types.GetProposalIDBytes(proposalID)

store.Set(types.InactiveProposalQueueKey(proposalID, endTime), bz)
}

/ RemoveFromInactiveProposalQueue removes a proposalID from the Inactive Proposal Queue
func (keeper Keeper)

RemoveFromInactiveProposalQueue(ctx sdk.Context, proposalID uint64, endTime time.Time) {
    store := ctx.KVStore(keeper.storeKey)

store.Delete(types.InactiveProposalQueueKey(proposalID, endTime))
}

/ Iterators

/ IterateActiveProposalsQueue iterates over the proposals in the active proposal queue
/ and performs a callback function
func (keeper Keeper)

IterateActiveProposalsQueue(ctx sdk.Context, endTime time.Time, cb func(proposal v1.Proposal) (stop bool)) {
    iterator := keeper.ActiveProposalQueueIterator(ctx, endTime)

defer iterator.Close()
    for ; iterator.Valid(); iterator.Next() {
    proposalID, _ := types.SplitActiveProposalQueueKey(iterator.Key())

proposal, found := keeper.GetProposal(ctx, proposalID)
    if !found {
    panic(fmt.Sprintf("proposal %d does not exist", proposalID))
}
    if cb(proposal) {
    break
}
	
}
}

/ IterateInactiveProposalsQueue iterates over the proposals in the inactive proposal queue
/ and performs a callback function
func (keeper Keeper)

IterateInactiveProposalsQueue(ctx sdk.Context, endTime time.Time, cb func(proposal v1.Proposal) (stop bool)) {
    iterator := keeper.InactiveProposalQueueIterator(ctx, endTime)

defer iterator.Close()
    for ; iterator.Valid(); iterator.Next() {
    proposalID, _ := types.SplitInactiveProposalQueueKey(iterator.Key())

proposal, found := keeper.GetProposal(ctx, proposalID)
    if !found {
    panic(fmt.Sprintf("proposal %d does not exist", proposalID))
}
    if cb(proposal) {
    break
}
	
}
}

/ ActiveProposalQueueIterator returns an sdk.Iterator for all the proposals in the Active Queue that expire by endTime
func (keeper Keeper)

ActiveProposalQueueIterator(ctx sdk.Context, endTime time.Time)

sdk.Iterator {
    store := ctx.KVStore(keeper.storeKey)

return store.Iterator(types.ActiveProposalQueuePrefix, sdk.PrefixEndBytes(types.ActiveProposalByTimeKey(endTime)))
}

/ InactiveProposalQueueIterator returns an sdk.Iterator for all the proposals in the Inactive Queue that expire by endTime
func (keeper Keeper)

InactiveProposalQueueIterator(ctx sdk.Context, endTime time.Time)

sdk.Iterator {
    store := ctx.KVStore(keeper.storeKey)

return store.Iterator(types.InactiveProposalQueuePrefix, sdk.PrefixEndBytes(types.InactiveProposalByTimeKey(endTime)))
}

/ assertMetadataLength returns an error if given metadata length
/ is greater than a pre-defined MaxMetadataLen.
func (keeper Keeper)

assertMetadataLength(metadata string)

error {
    if metadata != "" && uint64(len(metadata)) > keeper.config.MaxMetadataLen {
    return types.ErrMetadataTooLong.Wrapf("got metadata with length %d", len(metadata))
}

return nil
}
In order to only test x/gov, we mock the expected keepers and instantiate the Keeper with the mocked dependencies. Note that we may need to configure the mocked dependencies to return the expected values:
package keeper_test

import (
    
	"fmt"
    "testing"
    "cosmossdk.io/math"
    "github.com/golang/mock/gomock"
	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
	tmtime "github.com/tendermint/tendermint/types/time"
    "github.com/cosmos/cosmos-sdk/baseapp"
    "github.com/cosmos/cosmos-sdk/testutil"
    "github.com/cosmos/cosmos-sdk/testutil/testdata"
	sdk "github.com/cosmos/cosmos-sdk/types"
	moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
    "github.com/cosmos/cosmos-sdk/x/gov/keeper"
	govtestutil "github.com/cosmos/cosmos-sdk/x/gov/testutil"
    "github.com/cosmos/cosmos-sdk/x/gov/types"
	v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
    "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
	minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
)

var (
	_, _, addr   = testdata.KeyTestPubAddr()

govAcct      = authtypes.NewModuleAddress(types.ModuleName)

TestProposal = getTestProposal()
)

/ getTestProposal creates and returns a test proposal message.
func getTestProposal() []sdk.Msg {
    legacyProposalMsg, err := v1.NewLegacyContent(v1beta1.NewTextProposal("Title", "description"), authtypes.NewModuleAddress(types.ModuleName).String())
    if err != nil {
    panic(err)
}

return []sdk.Msg{
    banktypes.NewMsgSend(govAcct, addr, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000)))),
		legacyProposalMsg,
}
}

/ setupGovKeeper creates a govKeeper as well as all its dependencies.
func setupGovKeeper(t *testing.T) (
	*keeper.Keeper,
	*govtestutil.MockAccountKeeper,
	*govtestutil.MockBankKeeper,
	*govtestutil.MockStakingKeeper,
	moduletestutil.TestEncodingConfig,
	sdk.Context,
) {
    key := sdk.NewKVStoreKey(types.StoreKey)
    testCtx := testutil.DefaultContextWithDB(t, key, sdk.NewTransientStoreKey("transient_test"))
    ctx := testCtx.Ctx.WithBlockHeader(tmproto.Header{
    Time: tmtime.Now()
})
    encCfg := moduletestutil.MakeTestEncodingConfig()

v1.RegisterInterfaces(encCfg.InterfaceRegistry)

v1beta1.RegisterInterfaces(encCfg.InterfaceRegistry)

banktypes.RegisterInterfaces(encCfg.InterfaceRegistry)

	/ Create MsgServiceRouter, but don't populate it before creating the gov
	/ keeper.
    msr := baseapp.NewMsgServiceRouter()

	/ gomock initializations
    ctrl := gomock.NewController(t)
    acctKeeper := govtestutil.NewMockAccountKeeper(ctrl)
    bankKeeper := govtestutil.NewMockBankKeeper(ctrl)
    stakingKeeper := govtestutil.NewMockStakingKeeper(ctrl)

acctKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(govAcct).AnyTimes()

acctKeeper.EXPECT().GetModuleAccount(gomock.Any(), types.ModuleName).Return(authtypes.NewEmptyModuleAccount(types.ModuleName)).AnyTimes()

trackMockBalances(bankKeeper)

stakingKeeper.EXPECT().TokensFromConsensusPower(ctx, gomock.Any()).DoAndReturn(func(ctx sdk.Context, power int64)

math.Int {
    return sdk.TokensFromConsensusPower(power, math.NewIntFromUint64(1000000))
}).AnyTimes()

stakingKeeper.EXPECT().BondDenom(ctx).Return("stake").AnyTimes()

stakingKeeper.EXPECT().IterateBondedValidatorsByPower(gomock.Any(), gomock.Any()).AnyTimes()

stakingKeeper.EXPECT().IterateDelegations(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()

stakingKeeper.EXPECT().TotalBondedTokens(gomock.Any()).Return(math.NewInt(10000000)).AnyTimes()

	/ Gov keeper initializations
    govKeeper := keeper.NewKeeper(encCfg.Codec, key, acctKeeper, bankKeeper, stakingKeeper, msr, types.DefaultConfig(), govAcct.String())

govKeeper.SetProposalID(ctx, 1)
    govRouter := v1beta1.NewRouter() / Also register legacy gov handlers to test them too.
	govRouter.AddRoute(types.RouterKey, v1beta1.ProposalHandler)

govKeeper.SetLegacyRouter(govRouter)

govKeeper.SetParams(ctx, v1.DefaultParams())

	/ Register all handlers for the MegServiceRouter.
	msr.SetInterfaceRegistry(encCfg.InterfaceRegistry)

v1.RegisterMsgServer(msr, keeper.NewMsgServerImpl(govKeeper))

banktypes.RegisterMsgServer(msr, nil) / Nil is fine here as long as we never execute the proposal's Msgs.

	return govKeeper, acctKeeper, bankKeeper, stakingKeeper, encCfg, ctx
}

/ trackMockBalances sets up expected calls on the Mock BankKeeper, and also
/ locally tracks accounts balances (not modules balances).
func trackMockBalances(bankKeeper *govtestutil.MockBankKeeper) {
    balances := make(map[string]sdk.Coins)

	/ We don't track module account balances.
	bankKeeper.EXPECT().MintCoins(gomock.Any(), minttypes.ModuleName, gomock.Any()).AnyTimes()

bankKeeper.EXPECT().BurnCoins(gomock.Any(), types.ModuleName, gomock.Any()).AnyTimes()

bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), minttypes.ModuleName, types.ModuleName, gomock.Any()).AnyTimes()

	/ But we do track normal account balances.
	bankKeeper.EXPECT().SendCoinsFromAccountToModule(gomock.Any(), gomock.Any(), types.ModuleName, gomock.Any()).DoAndReturn(func(_ sdk.Context, sender sdk.AccAddress, _ string, coins sdk.Coins)

error {
    newBalance, negative := balances[sender.String()].SafeSub(coins...)
    if negative {
    return fmt.Errorf("not enough balance")
}

balances[sender.String()] = newBalance
		return nil
}).AnyTimes()

bankKeeper.EXPECT().SendCoinsFromModuleToAccount(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_ sdk.Context, module string, rcpt sdk.AccAddress, coins sdk.Coins)

error {
    balances[rcpt.String()] = balances[rcpt.String()].Add(coins...)

return nil
}).AnyTimes()

bankKeeper.EXPECT().GetAllBalances(gomock.Any(), gomock.Any()).DoAndReturn(func(_ sdk.Context, addr sdk.AccAddress)

sdk.Coins {
    return balances[addr.String()]
}).AnyTimes()
}
This allows us to test the x/gov module without having to import other modules.
package keeper_test

import (
    
	"testing"
    "github.com/stretchr/testify/require"
    "github.com/stretchr/testify/suite"
    "github.com/cosmos/cosmos-sdk/baseapp"
    "github.com/cosmos/cosmos-sdk/codec"
	simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
	sdk "github.com/cosmos/cosmos-sdk/types"
    "github.com/cosmos/cosmos-sdk/x/gov/keeper"
	govtestutil "github.com/cosmos/cosmos-sdk/x/gov/testutil"
    "github.com/cosmos/cosmos-sdk/x/gov/types"
	v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
    "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
	minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
)

type KeeperTestSuite struct {
    suite.Suite

	cdc               codec.Codec
	ctx               sdk.Context
	govKeeper         *keeper.Keeper
	acctKeeper        *govtestutil.MockAccountKeeper
	bankKeeper        *govtestutil.MockBankKeeper
	stakingKeeper     *govtestutil.MockStakingKeeper
	queryClient       v1.QueryClient
	legacyQueryClient v1beta1.QueryClient
	addrs             []sdk.AccAddress
	msgSrvr           v1.MsgServer
	legacyMsgSrvr     v1beta1.MsgServer
}

func (suite *KeeperTestSuite)

SetupSuite() {
    suite.reset()
}

func (suite *KeeperTestSuite)

reset() {
    govKeeper, acctKeeper, bankKeeper, stakingKeeper, encCfg, ctx := setupGovKeeper(suite.T())

	/ Populate the gov account with some coins, as the TestProposal we have
	/ is a MsgSend from the gov account.
    coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100000)))
    err := bankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, coins)

suite.NoError(err)

err = bankKeeper.SendCoinsFromModuleToModule(ctx, minttypes.ModuleName, types.ModuleName, coins)

suite.NoError(err)
    queryHelper := baseapp.NewQueryServerTestHelper(ctx, encCfg.InterfaceRegistry)

v1.RegisterQueryServer(queryHelper, govKeeper)
    legacyQueryHelper := baseapp.NewQueryServerTestHelper(ctx, encCfg.InterfaceRegistry)

v1beta1.RegisterQueryServer(legacyQueryHelper, keeper.NewLegacyQueryServer(govKeeper))
    queryClient := v1.NewQueryClient(queryHelper)
    legacyQueryClient := v1beta1.NewQueryClient(legacyQueryHelper)

suite.ctx = ctx
	suite.govKeeper = govKeeper
	suite.acctKeeper = acctKeeper
	suite.bankKeeper = bankKeeper
	suite.stakingKeeper = stakingKeeper
	suite.cdc = encCfg.Codec
	suite.queryClient = queryClient
	suite.legacyQueryClient = legacyQueryClient
	suite.msgSrvr = keeper.NewMsgServerImpl(suite.govKeeper)

suite.legacyMsgSrvr = keeper.NewLegacyMsgServerImpl(govAcct.String(), suite.msgSrvr)

suite.addrs = simtestutil.AddTestAddrsIncremental(bankKeeper, stakingKeeper, ctx, 3, sdk.NewInt(30000000))
}

func TestIncrementProposalNumber(t *testing.T) {
    govKeeper, _, _, _, _, ctx := setupGovKeeper(t)
    tp := TestProposal
	_, err := govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)
	_, err = govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)
	_, err = govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)
	_, err = govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)
	_, err = govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)

proposal6, err := govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)

require.Equal(t, uint64(6), proposal6.Id)
}

func TestProposalQueues(t *testing.T) {
    govKeeper, _, _, _, _, ctx := setupGovKeeper(t)

	/ create test proposals
    tp := TestProposal
	proposal, err := govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)
    inactiveIterator := govKeeper.InactiveProposalQueueIterator(ctx, *proposal.DepositEndTime)

require.True(t, inactiveIterator.Valid())
    proposalID := types.GetProposalIDFromBytes(inactiveIterator.Value())

require.Equal(t, proposalID, proposal.Id)

inactiveIterator.Close()

govKeeper.ActivateVotingPeriod(ctx, proposal)

proposal, ok := govKeeper.GetProposal(ctx, proposal.Id)

require.True(t, ok)
    activeIterator := govKeeper.ActiveProposalQueueIterator(ctx, *proposal.VotingEndTime)

require.True(t, activeIterator.Valid())

proposalID, _ = types.SplitActiveProposalQueueKey(activeIterator.Key())

require.Equal(t, proposalID, proposal.Id)

activeIterator.Close()
}

func TestKeeperTestSuite(t *testing.T) {
    suite.Run(t, new(KeeperTestSuite))
}
We can test then create unit tests using the newly created Keeper instance.
package keeper_test

import (
    
	"testing"
    "github.com/stretchr/testify/require"
    "github.com/stretchr/testify/suite"
    "github.com/cosmos/cosmos-sdk/baseapp"
    "github.com/cosmos/cosmos-sdk/codec"
	simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
	sdk "github.com/cosmos/cosmos-sdk/types"
    "github.com/cosmos/cosmos-sdk/x/gov/keeper"
	govtestutil "github.com/cosmos/cosmos-sdk/x/gov/testutil"
    "github.com/cosmos/cosmos-sdk/x/gov/types"
	v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
    "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
	minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
)

type KeeperTestSuite struct {
    suite.Suite

	cdc               codec.Codec
	ctx               sdk.Context
	govKeeper         *keeper.Keeper
	acctKeeper        *govtestutil.MockAccountKeeper
	bankKeeper        *govtestutil.MockBankKeeper
	stakingKeeper     *govtestutil.MockStakingKeeper
	queryClient       v1.QueryClient
	legacyQueryClient v1beta1.QueryClient
	addrs             []sdk.AccAddress
	msgSrvr           v1.MsgServer
	legacyMsgSrvr     v1beta1.MsgServer
}

func (suite *KeeperTestSuite)

SetupSuite() {
    suite.reset()
}

func (suite *KeeperTestSuite)

reset() {
    govKeeper, acctKeeper, bankKeeper, stakingKeeper, encCfg, ctx := setupGovKeeper(suite.T())

	/ Populate the gov account with some coins, as the TestProposal we have
	/ is a MsgSend from the gov account.
    coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100000)))
    err := bankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, coins)

suite.NoError(err)

err = bankKeeper.SendCoinsFromModuleToModule(ctx, minttypes.ModuleName, types.ModuleName, coins)

suite.NoError(err)
    queryHelper := baseapp.NewQueryServerTestHelper(ctx, encCfg.InterfaceRegistry)

v1.RegisterQueryServer(queryHelper, govKeeper)
    legacyQueryHelper := baseapp.NewQueryServerTestHelper(ctx, encCfg.InterfaceRegistry)

v1beta1.RegisterQueryServer(legacyQueryHelper, keeper.NewLegacyQueryServer(govKeeper))
    queryClient := v1.NewQueryClient(queryHelper)
    legacyQueryClient := v1beta1.NewQueryClient(legacyQueryHelper)

suite.ctx = ctx
	suite.govKeeper = govKeeper
	suite.acctKeeper = acctKeeper
	suite.bankKeeper = bankKeeper
	suite.stakingKeeper = stakingKeeper
	suite.cdc = encCfg.Codec
	suite.queryClient = queryClient
	suite.legacyQueryClient = legacyQueryClient
	suite.msgSrvr = keeper.NewMsgServerImpl(suite.govKeeper)

suite.legacyMsgSrvr = keeper.NewLegacyMsgServerImpl(govAcct.String(), suite.msgSrvr)

suite.addrs = simtestutil.AddTestAddrsIncremental(bankKeeper, stakingKeeper, ctx, 3, sdk.NewInt(30000000))
}

func TestIncrementProposalNumber(t *testing.T) {
    govKeeper, _, _, _, _, ctx := setupGovKeeper(t)
    tp := TestProposal
	_, err := govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)
	_, err = govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)
	_, err = govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)
	_, err = govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)
	_, err = govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)

proposal6, err := govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)

require.Equal(t, uint64(6), proposal6.Id)
}

func TestProposalQueues(t *testing.T) {
    govKeeper, _, _, _, _, ctx := setupGovKeeper(t)

	/ create test proposals
    tp := TestProposal
	proposal, err := govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)
    inactiveIterator := govKeeper.InactiveProposalQueueIterator(ctx, *proposal.DepositEndTime)

require.True(t, inactiveIterator.Valid())
    proposalID := types.GetProposalIDFromBytes(inactiveIterator.Value())

require.Equal(t, proposalID, proposal.Id)

inactiveIterator.Close()

govKeeper.ActivateVotingPeriod(ctx, proposal)

proposal, ok := govKeeper.GetProposal(ctx, proposal.Id)

require.True(t, ok)
    activeIterator := govKeeper.ActiveProposalQueueIterator(ctx, *proposal.VotingEndTime)

require.True(t, activeIterator.Valid())

proposalID, _ = types.SplitActiveProposalQueueKey(activeIterator.Key())

require.Equal(t, proposalID, proposal.Id)

activeIterator.Close()
}

func TestKeeperTestSuite(t *testing.T) {
    suite.Run(t, new(KeeperTestSuite))
}

Integration Tests

Integration tests are at the second level of the test pyramid. In the SDK, we locate our integration tests under /tests/integrations. The goal of these integration tests is to test how a component interacts with other dependencies. Compared to unit tests, integration tests do not mock dependencies. Instead, they use the direct dependencies of the component. This differs as well from end-to-end tests, which test the component with a full application. Integration tests interact with the tested module via the defined Msg and Query services. The result of the test can be verified by checking the state of the application, by checking the emitted events or the response. It is adviced to combine two of these methods to verify the result of the test. The SDK provides small helpers for quickly setting up an integration tests. These helpers can be found at Link.

Example

package integration_test

import (
    
	"fmt"
    "io"
    "cosmossdk.io/log"
	storetypes "cosmossdk.io/store/types"
    "github.com/cosmos/cosmos-sdk/runtime"
    "github.com/cosmos/cosmos-sdk/testutil/integration"
	moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
    "github.com/cosmos/cosmos-sdk/x/auth"
	authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
	authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    "github.com/cosmos/cosmos-sdk/x/mint"
	mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper"
	minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
    "github.com/google/go-cmp/cmp"
)

/ Example shows how to use the integration test framework to test the integration of a modules.
/ Panics are used in this example, but in a real test case, you should use the testing.T object and assertions.
func Example() {
	/ in this example we are testing the integration of the following modules:
	/ - mint, which directly depends on auth, bank and staking
    encodingCfg := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{
}, mint.AppModuleBasic{
})
    keys := storetypes.NewKVStoreKeys(authtypes.StoreKey, minttypes.StoreKey)
    authority := authtypes.NewModuleAddress("gov").String()
    accountKeeper := authkeeper.NewAccountKeeper(
		encodingCfg.Codec,
		runtime.NewKVStoreService(keys[authtypes.StoreKey]),
		authtypes.ProtoBaseAccount,
		map[string][]string{
    minttypes.ModuleName: {
    authtypes.Minter
}},
		"cosmos",
		authority,
	)

	/ subspace is nil because we don't test params (which is legacy anyway)
    authModule := auth.NewAppModule(encodingCfg.Codec, accountKeeper, authsims.RandomGenesisAccounts, nil)

	/ here bankkeeper and staking keeper is nil because we are not testing them
	/ subspace is nil because we don't test params (which is legacy anyway)
    mintKeeper := mintkeeper.NewKeeper(encodingCfg.Codec, keys[minttypes.StoreKey], nil, accountKeeper, nil, authtypes.FeeCollectorName, authority)
    mintModule := mint.NewAppModule(encodingCfg.Codec, mintKeeper, accountKeeper, nil, nil)

	/ create the application and register all the modules from the previous step
	/ replace the name and the logger by testing values in a real test case (e.g. t.Name()

and log.NewTestLogger(t))
    integrationApp := integration.NewIntegrationApp("example", log.NewLogger(io.Discard), keys, authModule, mintModule)

	/ register the message and query servers
	authtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), authkeeper.NewMsgServerImpl(accountKeeper))

minttypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), mintkeeper.NewMsgServerImpl(mintKeeper))

minttypes.RegisterQueryServer(integrationApp.QueryHelper(), mintKeeper)
    params := minttypes.DefaultParams()

params.BlocksPerYear = 10000

	/ now we can use the application to test a mint message
	result, err := integrationApp.RunMsg(&minttypes.MsgUpdateParams{
    Authority: authority,
    Params:    params,
})
    if err != nil {
    panic(err)
}

	/ in this example the result is an empty response, a nil check is enough
	/ in other cases, it is recommended to check the result value.
    if result == nil {
    panic(fmt.Errorf("unexpected nil result"))
}

	/ we now check the result
    resp := minttypes.MsgUpdateParamsResponse{
}

err = encodingCfg.Codec.Unmarshal(result.Value, &resp)
    if err != nil {
    panic(err)
}

	/ we should also check the state of the application
    got := mintKeeper.GetParams(integrationApp.SDKContext())
    if diff := cmp.Diff(got, params); diff != "" {
    panic(diff)
}

fmt.Println(got.BlocksPerYear)
	/ Output: 10000
}

/ ExampleOneModule shows how to use the integration test framework to test the integration of a single module.
/ That module has no dependency on other modules.
func Example_oneModule() {
	/ in this example we are testing the integration of the auth module:
    encodingCfg := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{
})
    keys := storetypes.NewKVStoreKeys(authtypes.StoreKey)
    authority := authtypes.NewModuleAddress("gov").String()
    accountKeeper := authkeeper.NewAccountKeeper(
		encodingCfg.Codec,
		runtime.NewKVStoreService(keys[authtypes.StoreKey]),
		authtypes.ProtoBaseAccount,
		map[string][]string{
    minttypes.ModuleName: {
    authtypes.Minter
}},
		"cosmos",
		authority,
	)

	/ subspace is nil because we don't test params (which is legacy anyway)
    authModule := auth.NewAppModule(encodingCfg.Codec, accountKeeper, authsims.RandomGenesisAccounts, nil)

	/ create the application and register all the modules from the previous step
	/ replace the name and the logger by testing values in a real test case (e.g. t.Name()

and log.NewTestLogger(t))
    integrationApp := integration.NewIntegrationApp("example-one-module", log.NewLogger(io.Discard), keys, authModule)

	/ register the message and query servers
	authtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), authkeeper.NewMsgServerImpl(accountKeeper))
    params := authtypes.DefaultParams()

params.MaxMemoCharacters = 1000

	/ now we can use the application to test a mint message
	result, err := integrationApp.RunMsg(&authtypes.MsgUpdateParams{
    Authority: authority,
    Params:    params,
})
    if err != nil {
    panic(err)
}

	/ in this example the result is an empty response, a nil check is enough
	/ in other cases, it is recommended to check the result value.
    if result == nil {
    panic(fmt.Errorf("unexpected nil result"))
}

	/ we now check the result
    resp := authtypes.MsgUpdateParamsResponse{
}

err = encodingCfg.Codec.Unmarshal(result.Value, &resp)
    if err != nil {
    panic(err)
}

	/ we should also check the state of the application
    got := accountKeeper.GetParams(integrationApp.SDKContext())
    if diff := cmp.Diff(got, params); diff != "" {
    panic(diff)
}

fmt.Println(got.MaxMemoCharacters)
	/ Output: 1000
}

Deterministic and Regression tests

Tests are written for queries in the Cosmos SDK which have module_query_safe Protobuf annotation. Each query is tested using 2 methods:
  • Use property-based testing with the rapid library. The property that is tested is that the query response and gas consumption are the same upon 1000 query calls.
  • Regression tests are written with hardcoded responses and gas, and verify they don’t change upon 1000 calls and between SDK patch versions.
Here’s an example of regression tests:
package keeper_test

import (
    
	"testing"
    "github.com/stretchr/testify/suite"
	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    "pgregory.net/rapid"
    "github.com/cosmos/cosmos-sdk/baseapp"
	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
    "github.com/cosmos/cosmos-sdk/testutil/configurator"
	simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
    "github.com/cosmos/cosmos-sdk/testutil/testdata"
	sdk "github.com/cosmos/cosmos-sdk/types"
    "github.com/cosmos/cosmos-sdk/x/bank/keeper"
	banktestutil "github.com/cosmos/cosmos-sdk/x/bank/testutil"
	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
	minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"

	_ "github.com/cosmos/cosmos-sdk/x/auth"
	_ "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
	_ "github.com/cosmos/cosmos-sdk/x/bank"
	_ "github.com/cosmos/cosmos-sdk/x/consensus"
	_ "github.com/cosmos/cosmos-sdk/x/params"
	_ "github.com/cosmos/cosmos-sdk/x/staking"
)

type DeterministicTestSuite struct {
    suite.Suite

	ctx        sdk.Context
	bankKeeper keeper.BaseKeeper

	queryClient banktypes.QueryClient
}

var (
	denomRegex   = sdk.DefaultCoinDenomRegex()

addr1        = sdk.MustAccAddressFromBech32("cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5")

coin1        = sdk.NewCoin("denom", sdk.NewInt(10))

metadataAtom = banktypes.Metadata{
    Description: "The native staking token of the Cosmos Hub.",
    DenomUnits: []*banktypes.DenomUnit{
			{
    Denom:    "uatom",
    Exponent: 0,
    Aliases:  []string{"microatom"
},
},
			{
    Denom:    "atom",
    Exponent: 6,
    Aliases:  []string{"ATOM"
},
},
},
    Base:    "uatom",
    Display: "atom",
}
)

func TestDeterministicTestSuite(t *testing.T) {
    suite.Run(t, new(DeterministicTestSuite))
}

func (suite *DeterministicTestSuite)

SetupTest() {
    var interfaceRegistry codectypes.InterfaceRegistry

	app, err := simtestutil.Setup(
		configurator.NewAppConfig(
			configurator.AuthModule(),
			configurator.TxModule(),
			configurator.ParamsModule(),
			configurator.ConsensusModule(),
			configurator.BankModule(),
			configurator.StakingModule(),
		),
		&suite.bankKeeper,
		&interfaceRegistry,
	)

suite.Require().NoError(err)
    ctx := app.BaseApp.NewContext(false, tmproto.Header{
})

suite.ctx = ctx
    queryHelper := baseapp.NewQueryServerTestHelper(ctx, interfaceRegistry)

banktypes.RegisterQueryServer(queryHelper, suite.bankKeeper)

suite.queryClient = banktypes.NewQueryClient(queryHelper)
}

func (suite *DeterministicTestSuite)

fundAccount(addr sdk.AccAddress, coin ...sdk.Coin) {
    err := banktestutil.FundAccount(suite.bankKeeper, suite.ctx, addr, sdk.NewCoins(coin...))

suite.Require().NoError(err)
}

func (suite *DeterministicTestSuite)

getCoin(t *rapid.T)

sdk.Coin {
    return sdk.NewCoin(
		rapid.StringMatching(denomRegex).Draw(t, "denom"),
		sdk.NewInt(rapid.Int64Min(1).Draw(t, "amount")),
	)
}

func (suite *DeterministicTestSuite)

TestGRPCQueryBalance() {
    rapid.Check(suite.T(), func(t *rapid.T) {
    addr := testdata.AddressGenerator(t).Draw(t, "address")
    coin := suite.getCoin(t)

suite.fundAccount(addr, coin)
    req := banktypes.NewQueryBalanceRequest(addr, coin.GetDenom())

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.Balance, 0, true)
})

suite.fundAccount(addr1, coin1)
    req := banktypes.NewQueryBalanceRequest(addr1, coin1.GetDenom())

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.Balance, 1087, false)
}

func (suite *DeterministicTestSuite)

TestGRPCQueryAllBalances() {
    rapid.Check(suite.T(), func(t *rapid.T) {
    addr := testdata.AddressGenerator(t).Draw(t, "address")
    numCoins := rapid.IntRange(1, 10).Draw(t, "num-count")
    coins := make(sdk.Coins, 0, numCoins)
    for i := 0; i < numCoins; i++ {
    coin := suite.getCoin(t)

			/ NewCoins sorts the denoms
			coins = sdk.NewCoins(append(coins, coin)...)
}

suite.fundAccount(addr, coins...)
    req := banktypes.NewQueryAllBalancesRequest(addr, testdata.PaginationGenerator(t, uint64(numCoins)).Draw(t, "pagination"))

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.AllBalances, 0, true)
})
    coins := sdk.NewCoins(
		sdk.NewCoin("stake", sdk.NewInt(10)),
		sdk.NewCoin("denom", sdk.NewInt(100)),
	)

suite.fundAccount(addr1, coins...)
    req := banktypes.NewQueryAllBalancesRequest(addr1, nil)

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.AllBalances, 357, false)
}

func (suite *DeterministicTestSuite)

TestGRPCQuerySpendableBalances() {
    rapid.Check(suite.T(), func(t *rapid.T) {
    addr := testdata.AddressGenerator(t).Draw(t, "address")
    numCoins := rapid.IntRange(1, 10).Draw(t, "num-count")
    coins := make(sdk.Coins, 0, numCoins)
    for i := 0; i < numCoins; i++ {
    coin := sdk.NewCoin(
				rapid.StringMatching(denomRegex).Draw(t, "denom"),
				sdk.NewInt(rapid.Int64Min(1).Draw(t, "amount")),
			)

			/ NewCoins sorts the denoms
			coins = sdk.NewCoins(append(coins, coin)...)
}
    err := banktestutil.FundAccount(suite.bankKeeper, suite.ctx, addr, coins)

suite.Require().NoError(err)
    req := banktypes.NewQuerySpendableBalancesRequest(addr, testdata.PaginationGenerator(t, uint64(numCoins)).Draw(t, "pagination"))

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.SpendableBalances, 0, true)
})
    coins := sdk.NewCoins(
		sdk.NewCoin("stake", sdk.NewInt(10)),
		sdk.NewCoin("denom", sdk.NewInt(100)),
	)
    err := banktestutil.FundAccount(suite.bankKeeper, suite.ctx, addr1, coins)

suite.Require().NoError(err)
    req := banktypes.NewQuerySpendableBalancesRequest(addr1, nil)

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.SpendableBalances, 2032, false)
}

func (suite *DeterministicTestSuite)

TestGRPCQueryTotalSupply() {
    res, err := suite.queryClient.TotalSupply(suite.ctx, &banktypes.QueryTotalSupplyRequest{
})

suite.Require().NoError(err)
    initialSupply := res.GetSupply()

rapid.Check(suite.T(), func(t *rapid.T) {
    numCoins := rapid.IntRange(1, 3).Draw(t, "num-count")
    coins := make(sdk.Coins, 0, numCoins)
    for i := 0; i < numCoins; i++ {
    coin := sdk.NewCoin(
				rapid.StringMatching(denomRegex).Draw(t, "denom"),
				sdk.NewInt(rapid.Int64Min(1).Draw(t, "amount")),
			)

coins = coins.Add(coin)
}

suite.Require().NoError(suite.bankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, coins))

initialSupply = initialSupply.Add(coins...)
    req := &banktypes.QueryTotalSupplyRequest{
    Pagination: testdata.PaginationGenerator(t, uint64(len(initialSupply))).Draw(t, "pagination"),
}

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.TotalSupply, 0, true)
})

suite.SetupTest() / reset
    coins := sdk.NewCoins(
		sdk.NewCoin("foo", sdk.NewInt(10)),
		sdk.NewCoin("bar", sdk.NewInt(100)),
	)

suite.Require().NoError(suite.bankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, coins))
    req := &banktypes.QueryTotalSupplyRequest{
}

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.TotalSupply, 243, false)
}

func (suite *DeterministicTestSuite)

TestGRPCQueryTotalSupplyOf() {
    rapid.Check(suite.T(), func(t *rapid.T) {
    coin := sdk.NewCoin(
			rapid.StringMatching(denomRegex).Draw(t, "denom"),
			sdk.NewInt(rapid.Int64Min(1).Draw(t, "amount")),
		)

suite.Require().NoError(suite.bankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, sdk.NewCoins(coin)))
    req := &banktypes.QuerySupplyOfRequest{
    Denom: coin.GetDenom()
}

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.SupplyOf, 0, true)
})
    coin := sdk.NewCoin("bar", sdk.NewInt(100))

suite.Require().NoError(suite.bankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, sdk.NewCoins(coin)))
    req := &banktypes.QuerySupplyOfRequest{
    Denom: coin.GetDenom()
}

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.SupplyOf, 1021, false)
}

func (suite *DeterministicTestSuite)

TestGRPCQueryParams() {
    rapid.Check(suite.T(), func(t *rapid.T) {
    enabledStatus := banktypes.SendEnabled{
    Denom:   rapid.StringMatching(denomRegex).Draw(t, "denom"),
    Enabled: rapid.Bool().Draw(t, "status"),
}
    params := banktypes.Params{
    SendEnabled:        []*banktypes.SendEnabled{&enabledStatus
},
    DefaultSendEnabled: rapid.Bool().Draw(t, "send"),
}

suite.bankKeeper.SetParams(suite.ctx, params)
    req := &banktypes.QueryParamsRequest{
}

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.Params, 0, true)
})
    enabledStatus := banktypes.SendEnabled{
    Denom:   "denom",
    Enabled: true,
}
    params := banktypes.Params{
    SendEnabled:        []*banktypes.SendEnabled{&enabledStatus
},
    DefaultSendEnabled: false,
}

suite.bankKeeper.SetParams(suite.ctx, params)
    req := &banktypes.QueryParamsRequest{
}

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.Params, 1003, false)
}

func (suite *DeterministicTestSuite)

createAndReturnMetadatas(t *rapid.T, count int) []banktypes.Metadata {
    denomsMetadata := make([]banktypes.Metadata, 0, count)
    for i := 0; i < count; i++ {
    denom := rapid.StringMatching(denomRegex).Draw(t, "denom")
    aliases := rapid.SliceOf(rapid.String()).Draw(t, "aliases")
		/ In the GRPC server code, empty arrays are returned as nil
    if len(aliases) == 0 {
    aliases = nil
}
    metadata := banktypes.Metadata{
    Description: rapid.StringN(1, 100, 100).Draw(t, "desc"),
    DenomUnits: []*banktypes.DenomUnit{
				{
    Denom:    denom,
    Exponent: rapid.Uint32().Draw(t, "exponent"),
    Aliases:  aliases,
},
},
    Base:    denom,
    Display: denom,
    Name:    rapid.String().Draw(t, "name"),
    Symbol:  rapid.String().Draw(t, "symbol"),
    URI:     rapid.String().Draw(t, "uri"),
    URIHash: rapid.String().Draw(t, "uri-hash"),
}

denomsMetadata = append(denomsMetadata, metadata)
}

return denomsMetadata
}

func (suite *DeterministicTestSuite)

TestGRPCDenomsMetadata() {
    rapid.Check(suite.T(), func(t *rapid.T) {
    count := rapid.IntRange(1, 3).Draw(t, "count")
    denomsMetadata := suite.createAndReturnMetadatas(t, count)

suite.Require().Len(denomsMetadata, count)
    for i := 0; i < count; i++ {
    suite.bankKeeper.SetDenomMetaData(suite.ctx, denomsMetadata[i])
}
    req := &banktypes.QueryDenomsMetadataRequest{
    Pagination: testdata.PaginationGenerator(t, uint64(count)).Draw(t, "pagination"),
}

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.DenomsMetadata, 0, true)
})

suite.SetupTest() / reset

	suite.bankKeeper.SetDenomMetaData(suite.ctx, metadataAtom)
    req := &banktypes.QueryDenomsMetadataRequest{
}

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.DenomsMetadata, 660, false)
}

func (suite *DeterministicTestSuite)

TestGRPCDenomMetadata() {
    rapid.Check(suite.T(), func(t *rapid.T) {
    denomMetadata := suite.createAndReturnMetadatas(t, 1)

suite.Require().Len(denomMetadata, 1)

suite.bankKeeper.SetDenomMetaData(suite.ctx, denomMetadata[0])
    req := &banktypes.QueryDenomMetadataRequest{
    Denom: denomMetadata[0].Base,
}

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.DenomMetadata, 0, true)
})

suite.bankKeeper.SetDenomMetaData(suite.ctx, metadataAtom)
    req := &banktypes.QueryDenomMetadataRequest{
    Denom: metadataAtom.Base,
}

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.DenomMetadata, 1300, false)
}

func (suite *DeterministicTestSuite)

TestGRPCSendEnabled() {
    allDenoms := []string{
}

rapid.Check(suite.T(), func(t *rapid.T) {
    count := rapid.IntRange(0, 10).Draw(t, "count")
    denoms := make([]string, 0, count)
    for i := 0; i < count; i++ {
    coin := banktypes.SendEnabled{
    Denom:   rapid.StringMatching(denomRegex).Draw(t, "denom"),
    Enabled: rapid.Bool().Draw(t, "enabled-status"),
}

suite.bankKeeper.SetSendEnabled(suite.ctx, coin.Denom, coin.Enabled)

denoms = append(denoms, coin.Denom)
}

allDenoms = append(allDenoms, denoms...)
    req := &banktypes.QuerySendEnabledRequest{
    Denoms: denoms,
			/ Pagination is only taken into account when `denoms` is an empty array
			Pagination: testdata.PaginationGenerator(t, uint64(len(allDenoms))).Draw(t, "pagination"),
}

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.SendEnabled, 0, true)
})

coin1 := banktypes.SendEnabled{
    Denom:   "falsecoin",
    Enabled: false,
}

coin2 := banktypes.SendEnabled{
    Denom:   "truecoin",
    Enabled: true,
}

suite.bankKeeper.SetSendEnabled(suite.ctx, coin1.Denom, false)

suite.bankKeeper.SetSendEnabled(suite.ctx, coin2.Denom, true)
    req := &banktypes.QuerySendEnabledRequest{
    Denoms: []string{
    coin1.GetDenom(), coin2.GetDenom()
},
}

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.SendEnabled, 4063, false)
}

func (suite *DeterministicTestSuite)

TestGRPCDenomOwners() {
    rapid.Check(suite.T(), func(t *rapid.T) {
    denom := rapid.StringMatching(denomRegex).Draw(t, "denom")
    numAddr := rapid.IntRange(1, 10).Draw(t, "number-address")
    for i := 0; i < numAddr; i++ {
    addr := testdata.AddressGenerator(t).Draw(t, "address")
    coin := sdk.NewCoin(
				denom,
				sdk.NewInt(rapid.Int64Min(1).Draw(t, "amount")),
			)
    err := banktestutil.FundAccount(suite.bankKeeper, suite.ctx, addr, sdk.NewCoins(coin))

suite.Require().NoError(err)
}
    req := &banktypes.QueryDenomOwnersRequest{
    Denom:      denom,
    Pagination: testdata.PaginationGenerator(t, uint64(numAddr)).Draw(t, "pagination"),
}

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.DenomOwners, 0, true)
})
    denomOwners := []*banktypes.DenomOwner{
		{
    Address: "cosmos1qg65a9q6k2sqq7l3ycp428sqqpmqcucgzze299",
    Balance: coin1,
},
		{
    Address: "cosmos1qglnsqgpq48l7qqzgs8qdshr6fh3gqq9ej3qut",
    Balance: coin1,
},
}
    for i := 0; i < len(denomOwners); i++ {
    addr, err := sdk.AccAddressFromBech32(denomOwners[i].Address)

suite.Require().NoError(err)

err = banktestutil.FundAccount(suite.bankKeeper, suite.ctx, addr, sdk.NewCoins(coin1))

suite.Require().NoError(err)
}
    req := &banktypes.QueryDenomOwnersRequest{
    Denom: coin1.GetDenom(),
}

testdata.DeterministicIterations(suite.ctx, suite.Require(), req, suite.queryClient.DenomOwners, 2525, false)
}

Simulations

Simulations uses as well a minimal application, built with depinject:
You can as well use the AppConfig configurator for creating an AppConfig inline. There is no difference between those two ways, use whichever you prefer.
Following is an example for x/gov/ simulations:
package simulation_test

import (
    
	"fmt"
    "math/rand"
    "testing"
    "time"
    "github.com/stretchr/testify/require"
	abci "github.com/tendermint/tendermint/abci/types"
	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    "github.com/cosmos/cosmos-sdk/codec"
    "github.com/cosmos/cosmos-sdk/runtime"
    "github.com/cosmos/cosmos-sdk/testutil/configurator"
	simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
	sdk "github.com/cosmos/cosmos-sdk/types"
	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
	_ "github.com/cosmos/cosmos-sdk/x/auth"
	authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
	_ "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
	_ "github.com/cosmos/cosmos-sdk/x/bank"
	bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
    "github.com/cosmos/cosmos-sdk/x/bank/testutil"
	_ "github.com/cosmos/cosmos-sdk/x/consensus"
	govcodec "github.com/cosmos/cosmos-sdk/x/gov/codec"
    "github.com/cosmos/cosmos-sdk/x/gov/keeper"
    "github.com/cosmos/cosmos-sdk/x/gov/simulation"
    "github.com/cosmos/cosmos-sdk/x/gov/types"
	v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
    "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
	_ "github.com/cosmos/cosmos-sdk/x/params"
	_ "github.com/cosmos/cosmos-sdk/x/staking"
	stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
)

type MockWeightedProposalContent struct {
    n int
}

func (m MockWeightedProposalContent)

AppParamsKey()

string {
    return fmt.Sprintf("AppParamsKey-%d", m.n)
}

func (m MockWeightedProposalContent)

DefaultWeight()

int {
    return m.n
}

func (m MockWeightedProposalContent)

ContentSimulatorFn()

simtypes.ContentSimulatorFn {
    return func(r *rand.Rand, _ sdk.Context, _ []simtypes.Account)

simtypes.Content {
    return v1beta1.NewTextProposal(
			fmt.Sprintf("title-%d: %s", m.n, simtypes.RandStringOfLength(r, 100)),
			fmt.Sprintf("description-%d: %s", m.n, simtypes.RandStringOfLength(r, 4000)),
		)
}
}

/ make sure the MockWeightedProposalContent satisfied the WeightedProposalContent interface
var _ simtypes.WeightedProposalContent = MockWeightedProposalContent{
}

func mockWeightedProposalContent(n int) []simtypes.WeightedProposalContent {
    wpc := make([]simtypes.WeightedProposalContent, n)
    for i := 0; i < n; i++ {
    wpc[i] = MockWeightedProposalContent{
    i
}
	
}

return wpc
}

/ TestWeightedOperations tests the weights of the operations.
func TestWeightedOperations(t *testing.T) {
    suite, ctx := createTestSuite(t, false)
    app := suite.App
	ctx.WithChainID("test-chain")
    cdc := suite.cdc
    appParams := make(simtypes.AppParams)
    weightesOps := simulation.WeightedOperations(appParams, cdc, suite.AccountKeeper,
		suite.BankKeeper, suite.GovKeeper, mockWeightedProposalContent(3),
	)

	/ setup 3 accounts
    s := rand.NewSource(1)
    r := rand.New(s)
    accs := getTestingAccounts(t, r, suite.AccountKeeper, suite.BankKeeper, suite.StakingKeeper, ctx, 3)
    expected := []struct {
    weight     int
		opMsgRoute string
		opMsgName  string
}{
		{0, types.ModuleName, simulation.TypeMsgSubmitProposal
},
		{1, types.ModuleName, simulation.TypeMsgSubmitProposal
},
		{2, types.ModuleName, simulation.TypeMsgSubmitProposal
},
		{
    simulation.DefaultWeightMsgDeposit, types.ModuleName, simulation.TypeMsgDeposit
},
		{
    simulation.DefaultWeightMsgVote, types.ModuleName, simulation.TypeMsgVote
},
		{
    simulation.DefaultWeightMsgVoteWeighted, types.ModuleName, simulation.TypeMsgVoteWeighted
},
}
    for i, w := range weightesOps {
    operationMsg, _, _ := w.Op()(r, app.BaseApp, ctx, accs, ctx.ChainID())
		/ require.NoError(t, err) / TODO check if it should be NoError

		/ the following checks are very much dependent from the ordering of the output given
		/ by WeightedOperations. if the ordering in WeightedOperations changes some tests
		/ will fail
		require.Equal(t, expected[i].weight, w.Weight(), "weight should be the same")

require.Equal(t, expected[i].opMsgRoute, operationMsg.Route, "route should be the same")

require.Equal(t, expected[i].opMsgName, operationMsg.Name, "operation Msg name should be the same")
}
}

/ TestSimulateMsgSubmitProposal tests the normal scenario of a valid message of type TypeMsgSubmitProposal.
/ Abnormal scenarios, where errors occur, are not tested here.
func TestSimulateMsgSubmitProposal(t *testing.T) {
    suite, ctx := createTestSuite(t, false)
    app := suite.App

	/ setup 3 accounts
    s := rand.NewSource(1)
    r := rand.New(s)
    accounts := getTestingAccounts(t, r, suite.AccountKeeper, suite.BankKeeper, suite.StakingKeeper, ctx, 3)

	/ begin a new block
	app.BeginBlock(abci.RequestBeginBlock{
    Header: tmproto.Header{
    Height: app.LastBlockHeight() + 1,
    AppHash: app.LastCommitID().Hash
}})

	/ execute operation
    op := simulation.SimulateMsgSubmitProposal(suite.AccountKeeper, suite.BankKeeper, suite.GovKeeper, MockWeightedProposalContent{3
}.ContentSimulatorFn())

operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "")

require.NoError(t, err)

var msg v1.MsgSubmitProposal
	err = govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)

require.NoError(t, err)

require.True(t, operationMsg.OK)

require.Equal(t, "cosmos1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7u4x9a0", msg.Proposer)

require.NotEqual(t, len(msg.InitialDeposit), 0)

require.Equal(t, "2686011stake", msg.InitialDeposit[0].String())

require.Equal(t, "title-3: ZBSpYuLyYggwexjxusrBqDOTtGTOWeLrQKjLxzIivHSlcxgdXhhuTSkuxKGLwQvuyNhYFmBZHeAerqyNEUzXPFGkqEGqiQWIXnku", msg.Messages[0].GetCachedValue().(*v1.MsgExecLegacyContent).Content.GetCachedValue().(v1beta1.Content).GetTitle())

require.Equal(t, "description-3: NJWzHdBNpAXKJPHWQdrGYcAHSctgVlqwqHoLfHsXUdStwfefwzqLuKEhmMyYLdbZrcPgYqjNHxPexsruwEGStAneKbWkQDDIlCWBLSiAASNhZqNFlPtfqPJoxKsgMdzjWqLWdqKQuJqWPMvwPQWZUtVMOTMYKJbfdlZsjdsomuScvDmbDkgRualsxDvRJuCAmPOXitIbcyWsKGSdrEunFAOdmXnsuyFVgJqEjbklvmwrUlsxjRSfKZxGcpayDdgoFcnVSutxjRgOSFzPwidAjubMncNweqpbxhXGchpZUxuFDOtpnhNUycJICRYqsPhPSCjPTWZFLkstHWJxvdPEAyEIxXgLwbNOjrgzmaujiBABBIXvcXpLrbcEWNNQsbjvgJFgJkflpRohHUutvnaUqoopuKjTDaemDeSdqbnOzcfJpcTuAQtZoiLZOoAIlboFDAeGmSNwkvObPRvRWQgWkGkxwtPauYgdkmypLjbqhlHJIQTntgWjXwZdOyYEdQRRLfMSdnxqppqUofqLbLQDUjwKVKfZJUJQPsWIPwIVaSTrmKskoAhvmZyJgeRpkaTfGgrJzAigcxtfshmiDCFkuiluqtMOkidknnTBtumyJYlIsWLnCQclqdVmikUoMOPdPWwYbJxXyqUVicNxFxyqJTenNblyyKSdlCbiXxUiYUiMwXZASYfvMDPFgxniSjWaZTjHkqlJvtBsXqwPpyVxnJVGFWhfSxgOcduoxkiopJvFjMmFabrGYeVtTXLhxVUEiGwYUvndjFGzDVntUvibiyZhfMQdMhgsiuysLMiePBNXifRLMsSmXPkwlPloUbJveCvUlaalhZHuvdkCnkSHbMbmOnrfEGPwQiACiPlnihiaOdbjPqPiTXaHDoJXjSlZmltGqNHHNrcKdlFSCdmVOuvDcBLdSklyGJmcLTbSFtALdGlPkqqecJrpLCXNPWefoTJNgEJlyMEPneVaxxduAAEqQpHWZodWyRkDAxzyMnFMcjSVqeRXLqsNyNtQBbuRvunZflWSbbvXXdkyLikYqutQhLPONXbvhcQZJPSWnOulqQaXmbfFxAkqfYeseSHOQidHwbcsOaMnSrrmGjjRmEMQNuknupMxJiIeVjmgZvbmjPIQTEhQFULQLBMPrxcFPvBinaOPYWGvYGRKxLZdwamfRQQFngcdSlvwjfaPbURasIsGJVHtcEAxnIIrhSriiXLOlbEBLXFElXJFGxHJczRBIxAuPKtBisjKBwfzZFagdNmjdwIRvwzLkFKWRTDPxJCmpzHUcrPiiXXHnOIlqNVoGSXZewdnCRhuxeYGPVTfrNTQNOxZmxInOazUYNTNDgzsxlgiVEHPKMfbesvPHUqpNkUqbzeuzfdrsuLDpKHMUbBMKczKKWOdYoIXoPYtEjfOnlQLoGnbQUCuERdEFaptwnsHzTJDsuZkKtzMpFaZobynZdzNydEeJJHDYaQcwUxcqvwfWwNUsCiLvkZQiSfzAHftYgAmVsXgtmcYgTqJIawstRYJrZdSxlfRiqTufgEQVambeZZmaAyRQbcmdjVUZZCgqDrSeltJGXPMgZnGDZqISrGDOClxXCxMjmKqEPwKHoOfOeyGmqWqihqjINXLqnyTesZePQRqaWDQNqpLgNrAUKulklmckTijUltQKuWQDwpLmDyxLppPVMwsmBIpOwQttYFMjgJQZLYFPmxWFLIeZihkRNnkzoypBICIxgEuYsVWGIGRbbxqVasYnstWomJnHwmtOhAFSpttRYYzBmyEtZXiCthvKvWszTXDbiJbGXMcrYpKAgvUVFtdKUfvdMfhAryctklUCEdjetjuGNfJjajZtvzdYaqInKtFPPLYmRaXPdQzxdSQfmZDEVHlHGEGNSPRFJuIfKLLfUmnHxHnRjmzQPNlqrXgifUdzAGKVabYqvcDeYoTYgPsBUqehrBhmQUgTvDnsdpuhUoxskDdppTsYMcnDIPSwKIqhXDCIxOuXrywahvVavvHkPuaenjLmEbMgrkrQLHEAwrhHkPRNvonNQKqprqOFVZKAtpRSpvQUxMoXCMZLSSbnLEFsjVfANdQNQVwTmGxqVjVqRuxREAhuaDrFgEZpYKhwWPEKBevBfsOIcaZKyykQafzmGPLRAKDtTcJxJVgiiuUkmyMYuDUNEUhBEdoBLJnamtLmMJQgmLiUELIhLpiEvpOXOvXCPUeldLFqkKOwfacqIaRcnnZvERKRMCKUkMABbDHytQqQblrvoxOZkwzosQfDKGtIdfcXRJNqlBNwOCWoQBcEWyqrMlYZIAXYJmLfnjoJepgSFvrgajaBAIksoyeHqgqbGvpAstMIGmIhRYGGNPRIfOQKsGoKgxtsidhTaAePRCBFqZgPDWCIkqOJezGVkjfYUCZTlInbxBXwUAVRsxHTQtJFnnpmMvXDYCVlEmnZBKhmmxQOIQzxFWpJQkQoSAYzTEiDWEOsVLNrbfzeHFRyeYATakQQWmFDLPbVMCJcWjFGJjfqCoVzlbNNEsqxdSmNPjTjHYOkuEMFLkXYGaoJlraLqayMeCsTjWNRDPBywBJLAPVkGQqTwApVVwYAetlwSbzsdHWsTwSIcctkyKDuRWYDQikRqsKTMJchrliONJeaZIzwPQrNbTwxsGdwuduvibtYndRwpdsvyCktRHFalvUuEKMqXbItfGcNGWsGzubdPMYayOUOINjpcFBeESdwpdlTYmrPsLsVDhpTzoMegKrytNVZkfJRPuDCUXxSlSthOohmsuxmIZUedzxKmowKOdXTMcEtdpHaPWgIsIjrViKrQOCONlSuazmLuCUjLltOGXeNgJKedTVrrVCpWYWHyVrdXpKgNaMJVjbXxnVMSChdWKuZdqpisvrkBJPoURDYxWOtpjzZoOpWzyUuYNhCzRoHsMjmmWDcXzQiHIyjwdhPNwiPqFxeUfMVFQGImhykFgMIlQEoZCaRoqSBXTSWAeDumdbsOGtATwEdZlLfoBKiTvodQBGOEcuATWXfiinSjPmJKcWgQrTVYVrwlyMWhxqNbCMpIQNoSMGTiWfPTCezUjYcdWppnsYJihLQCqbNLRGgqrwHuIvsazapTpoPZIyZyeeSueJuTIhpHMEJfJpScshJubJGfkusuVBgfTWQoywSSliQQSfbvaHKiLnyjdSbpMkdBgXepoSsHnCQaYuHQqZsoEOmJCiuQUpJkmfyfbIShzlZpHFmLCsbknEAkKXKfRTRnuwdBeuOGgFbJLbDksHVapaRayWzwoYBEpmrlAxrUxYMUekKbpjPNfjUCjhbdMAnJmYQVZBQZkFVweHDAlaqJjRqoQPoOMLhyvYCzqEuQsAFoxWrzRnTVjStPadhsESlERnKhpEPsfDxNvxqcOyIulaCkmPdambLHvGhTZzysvqFauEgkFRItPfvisehFmoBhQqmkfbHVsgfHXDPJVyhwPllQpuYLRYvGodxKjkarnSNgsXoKEMlaSKxKdcVgvOkuLcfLFfdtXGTclqfPOfeoVLbqcjcXCUEBgAGplrkgsmIEhWRZLlGPGCwKWRaCKMkBHTAcypUrYjWwCLtOPVygMwMANGoQwFnCqFrUGMCRZUGJKTZIGPyldsifauoMnJPLTcDHmilcmahlqOELaAUYDBuzsVywnDQfwRLGIWozYaOAilMBcObErwgTDNGWnwQMUgFFSKtPDMEoEQCTKVREqrXZSGLqwTMcxHfWotDllNkIJPMbXzjDVjPOOjCFuIvTyhXKLyhUScOXvYthRXpPfKwMhptXaxIxgqBoUqzrWbaoLTVpQoottZyPFfNOoMioXHRuFwMRYUiKvcWPkrayyTLOCFJlAyslDameIuqVAuxErqFPEWIScKpBORIuZqoXlZuTvAjEdlEWDODFRregDTqGNoFBIHxvimmIZwLfFyKUfEWAnNBdtdzDmTPXtpHRGdIbuucfTjOygZsTxPjfweXhSUkMhPjMaxKlMIJMOXcnQfyzeOcbWwNbeH", msg.Messages[0].GetCachedValue().(*v1.MsgExecLegacyContent).Content.GetCachedValue().(v1beta1.Content).GetDescription())

require.Equal(t, "gov", msg.Route())

require.Equal(t, simulation.TypeMsgSubmitProposal, msg.Type())
}

/ TestSimulateMsgDeposit tests the normal scenario of a valid message of type TypeMsgDeposit.
/ Abnormal scenarios, where errors occur, are not tested here.
func TestSimulateMsgDeposit(t *testing.T) {
    suite, ctx := createTestSuite(t, false)
    app := suite.App
    blockTime := time.Now().UTC()

ctx = ctx.WithBlockTime(blockTime)

	/ setup 3 accounts
    s := rand.NewSource(1)
    r := rand.New(s)
    accounts := getTestingAccounts(t, r, suite.AccountKeeper, suite.BankKeeper, suite.StakingKeeper, ctx, 3)

	/ setup a proposal
    content := v1beta1.NewTextProposal("Test", "description")

contentMsg, err := v1.NewLegacyContent(content, suite.GovKeeper.GetGovernanceAccount(ctx).GetAddress().String())

require.NoError(t, err)
    submitTime := ctx.BlockHeader().Time
    depositPeriod := suite.GovKeeper.GetParams(ctx).MaxDepositPeriod

	proposal, err := v1.NewProposal([]sdk.Msg{
    contentMsg
}, 1, "", submitTime, submitTime.Add(*depositPeriod), "text proposal", "description", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)

suite.GovKeeper.SetProposal(ctx, proposal)

	/ begin a new block
	app.BeginBlock(abci.RequestBeginBlock{
    Header: tmproto.Header{
    Height: app.LastBlockHeight() + 1,
    AppHash: app.LastCommitID().Hash,
    Time: blockTime
}})

	/ execute operation
    op := simulation.SimulateMsgDeposit(suite.AccountKeeper, suite.BankKeeper, suite.GovKeeper)

operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "")

require.NoError(t, err)

var msg v1.MsgDeposit
	err = govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)

require.NoError(t, err)

require.True(t, operationMsg.OK)

require.Equal(t, uint64(1), msg.ProposalId)

require.Equal(t, "cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r", msg.Depositor)

require.NotEqual(t, len(msg.Amount), 0)

require.Equal(t, "560969stake", msg.Amount[0].String())

require.Equal(t, "gov", msg.Route())

require.Equal(t, simulation.TypeMsgDeposit, msg.Type())
}

/ TestSimulateMsgVote tests the normal scenario of a valid message of type TypeMsgVote.
/ Abnormal scenarios, where errors occur, are not tested here.
func TestSimulateMsgVote(t *testing.T) {
    suite, ctx := createTestSuite(t, false)
    app := suite.App
    blockTime := time.Now().UTC()

ctx = ctx.WithBlockTime(blockTime)

	/ setup 3 accounts
    s := rand.NewSource(1)
    r := rand.New(s)
    accounts := getTestingAccounts(t, r, suite.AccountKeeper, suite.BankKeeper, suite.StakingKeeper, ctx, 3)

	/ setup a proposal
    govAcc := suite.GovKeeper.GetGovernanceAccount(ctx).GetAddress().String()

contentMsg, err := v1.NewLegacyContent(v1beta1.NewTextProposal("Test", "description"), govAcc)

require.NoError(t, err)
    submitTime := ctx.BlockHeader().Time
    depositPeriod := suite.GovKeeper.GetParams(ctx).MaxDepositPeriod

	proposal, err := v1.NewProposal([]sdk.Msg{
    contentMsg
}, 1, "", submitTime, submitTime.Add(*depositPeriod), "text proposal", "description", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)

suite.GovKeeper.ActivateVotingPeriod(ctx, proposal)

	/ begin a new block
	app.BeginBlock(abci.RequestBeginBlock{
    Header: tmproto.Header{
    Height: app.LastBlockHeight() + 1,
    AppHash: app.LastCommitID().Hash,
    Time: blockTime
}})

	/ execute operation
    op := simulation.SimulateMsgVote(suite.AccountKeeper, suite.BankKeeper, suite.GovKeeper)

operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "")

require.NoError(t, err)

var msg v1.MsgVote
	govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)

require.True(t, operationMsg.OK)

require.Equal(t, uint64(1), msg.ProposalId)

require.Equal(t, "cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r", msg.Voter)

require.Equal(t, v1.OptionYes, msg.Option)

require.Equal(t, "gov", msg.Route())

require.Equal(t, simulation.TypeMsgVote, msg.Type())
}

/ TestSimulateMsgVoteWeighted tests the normal scenario of a valid message of type TypeMsgVoteWeighted.
/ Abnormal scenarios, where errors occur, are not tested here.
func TestSimulateMsgVoteWeighted(t *testing.T) {
    suite, ctx := createTestSuite(t, false)
    app := suite.App
    blockTime := time.Now().UTC()

ctx = ctx.WithBlockTime(blockTime)

	/ setup 3 accounts
    s := rand.NewSource(1)
    r := rand.New(s)
    accounts := getTestingAccounts(t, r, suite.AccountKeeper, suite.BankKeeper, suite.StakingKeeper, ctx, 3)

	/ setup a proposal
    govAcc := suite.GovKeeper.GetGovernanceAccount(ctx).GetAddress().String()

contentMsg, err := v1.NewLegacyContent(v1beta1.NewTextProposal("Test", "description"), govAcc)

require.NoError(t, err)
    submitTime := ctx.BlockHeader().Time
    depositPeriod := suite.GovKeeper.GetParams(ctx).MaxDepositPeriod

	proposal, err := v1.NewProposal([]sdk.Msg{
    contentMsg
}, 1, "", submitTime, submitTime.Add(*depositPeriod), "text proposal", "test", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)

suite.GovKeeper.ActivateVotingPeriod(ctx, proposal)

	/ begin a new block
	app.BeginBlock(abci.RequestBeginBlock{
    Header: tmproto.Header{
    Height: app.LastBlockHeight() + 1,
    AppHash: app.LastCommitID().Hash,
    Time: blockTime
}})

	/ execute operation
    op := simulation.SimulateMsgVoteWeighted(suite.AccountKeeper, suite.BankKeeper, suite.GovKeeper)

operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "")

require.NoError(t, err)

var msg v1.MsgVoteWeighted
	govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)

require.True(t, operationMsg.OK)

require.Equal(t, uint64(1), msg.ProposalId)

require.Equal(t, "cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r", msg.Voter)

require.True(t, len(msg.Options) >= 1)

require.Equal(t, "gov", msg.Route())

require.Equal(t, simulation.TypeMsgVoteWeighted, msg.Type())
}

type suite struct {
    cdc           codec.Codec
	AccountKeeper authkeeper.AccountKeeper
	BankKeeper    bankkeeper.Keeper
	GovKeeper     *keeper.Keeper
	StakingKeeper *stakingkeeper.Keeper
	App           *runtime.App
}

/ returns context and an app with updated mint keeper
func createTestSuite(t *testing.T, isCheckTx bool) (suite, sdk.Context) {
    res := suite{
}

app, err := simtestutil.Setup(configurator.NewAppConfig(
		configurator.AuthModule(),
		configurator.TxModule(),
		configurator.ParamsModule(),
		configurator.BankModule(),
		configurator.StakingModule(),
		configurator.ConsensusModule(),
		configurator.GovModule(),
	), &res.AccountKeeper, &res.BankKeeper, &res.GovKeeper, &res.StakingKeeper, &res.cdc)

require.NoError(t, err)
    ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{
})

res.App = app
	return res, ctx
}

func getTestingAccounts(
	t *testing.T, r *rand.Rand,
	accountKeeper authkeeper.AccountKeeper, bankKeeper bankkeeper.Keeper, stakingKeeper *stakingkeeper.Keeper,
	ctx sdk.Context, n int,
) []simtypes.Account {
    accounts := simtypes.RandomAccounts(r, n)
    initAmt := stakingKeeper.TokensFromConsensusPower(ctx, 200)
    initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt))

	/ add coins to the accounts
    for _, account := range accounts {
    acc := accountKeeper.NewAccountWithAddress(ctx, account.Address)

accountKeeper.SetAccount(ctx, acc)

require.NoError(t, testutil.FundAccount(bankKeeper, ctx, account.Address, initCoins))
}

return accounts
}
package simulation_test

import (
    
	"fmt"
    "math/rand"
    "testing"
    "time"
    "github.com/stretchr/testify/require"
	abci "github.com/tendermint/tendermint/abci/types"
	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    "github.com/cosmos/cosmos-sdk/codec"
    "github.com/cosmos/cosmos-sdk/runtime"
    "github.com/cosmos/cosmos-sdk/testutil/configurator"
	simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
	sdk "github.com/cosmos/cosmos-sdk/types"
	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
	_ "github.com/cosmos/cosmos-sdk/x/auth"
	authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
	_ "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
	_ "github.com/cosmos/cosmos-sdk/x/bank"
	bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
    "github.com/cosmos/cosmos-sdk/x/bank/testutil"
	_ "github.com/cosmos/cosmos-sdk/x/consensus"
	govcodec "github.com/cosmos/cosmos-sdk/x/gov/codec"
    "github.com/cosmos/cosmos-sdk/x/gov/keeper"
    "github.com/cosmos/cosmos-sdk/x/gov/simulation"
    "github.com/cosmos/cosmos-sdk/x/gov/types"
	v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
    "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
	_ "github.com/cosmos/cosmos-sdk/x/params"
	_ "github.com/cosmos/cosmos-sdk/x/staking"
	stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
)

type MockWeightedProposalContent struct {
    n int
}

func (m MockWeightedProposalContent)

AppParamsKey()

string {
    return fmt.Sprintf("AppParamsKey-%d", m.n)
}

func (m MockWeightedProposalContent)

DefaultWeight()

int {
    return m.n
}

func (m MockWeightedProposalContent)

ContentSimulatorFn()

simtypes.ContentSimulatorFn {
    return func(r *rand.Rand, _ sdk.Context, _ []simtypes.Account)

simtypes.Content {
    return v1beta1.NewTextProposal(
			fmt.Sprintf("title-%d: %s", m.n, simtypes.RandStringOfLength(r, 100)),
			fmt.Sprintf("description-%d: %s", m.n, simtypes.RandStringOfLength(r, 4000)),
		)
}
}

/ make sure the MockWeightedProposalContent satisfied the WeightedProposalContent interface
var _ simtypes.WeightedProposalContent = MockWeightedProposalContent{
}

func mockWeightedProposalContent(n int) []simtypes.WeightedProposalContent {
    wpc := make([]simtypes.WeightedProposalContent, n)
    for i := 0; i < n; i++ {
    wpc[i] = MockWeightedProposalContent{
    i
}
	
}

return wpc
}

/ TestWeightedOperations tests the weights of the operations.
func TestWeightedOperations(t *testing.T) {
    suite, ctx := createTestSuite(t, false)
    app := suite.App
	ctx.WithChainID("test-chain")
    cdc := suite.cdc
    appParams := make(simtypes.AppParams)
    weightesOps := simulation.WeightedOperations(appParams, cdc, suite.AccountKeeper,
		suite.BankKeeper, suite.GovKeeper, mockWeightedProposalContent(3),
	)

	/ setup 3 accounts
    s := rand.NewSource(1)
    r := rand.New(s)
    accs := getTestingAccounts(t, r, suite.AccountKeeper, suite.BankKeeper, suite.StakingKeeper, ctx, 3)
    expected := []struct {
    weight     int
		opMsgRoute string
		opMsgName  string
}{
		{0, types.ModuleName, simulation.TypeMsgSubmitProposal
},
		{1, types.ModuleName, simulation.TypeMsgSubmitProposal
},
		{2, types.ModuleName, simulation.TypeMsgSubmitProposal
},
		{
    simulation.DefaultWeightMsgDeposit, types.ModuleName, simulation.TypeMsgDeposit
},
		{
    simulation.DefaultWeightMsgVote, types.ModuleName, simulation.TypeMsgVote
},
		{
    simulation.DefaultWeightMsgVoteWeighted, types.ModuleName, simulation.TypeMsgVoteWeighted
},
}
    for i, w := range weightesOps {
    operationMsg, _, _ := w.Op()(r, app.BaseApp, ctx, accs, ctx.ChainID())
		/ require.NoError(t, err) / TODO check if it should be NoError

		/ the following checks are very much dependent from the ordering of the output given
		/ by WeightedOperations. if the ordering in WeightedOperations changes some tests
		/ will fail
		require.Equal(t, expected[i].weight, w.Weight(), "weight should be the same")

require.Equal(t, expected[i].opMsgRoute, operationMsg.Route, "route should be the same")

require.Equal(t, expected[i].opMsgName, operationMsg.Name, "operation Msg name should be the same")
}
}

/ TestSimulateMsgSubmitProposal tests the normal scenario of a valid message of type TypeMsgSubmitProposal.
/ Abnormal scenarios, where errors occur, are not tested here.
func TestSimulateMsgSubmitProposal(t *testing.T) {
    suite, ctx := createTestSuite(t, false)
    app := suite.App

	/ setup 3 accounts
    s := rand.NewSource(1)
    r := rand.New(s)
    accounts := getTestingAccounts(t, r, suite.AccountKeeper, suite.BankKeeper, suite.StakingKeeper, ctx, 3)

	/ begin a new block
	app.BeginBlock(abci.RequestBeginBlock{
    Header: tmproto.Header{
    Height: app.LastBlockHeight() + 1,
    AppHash: app.LastCommitID().Hash
}})

	/ execute operation
    op := simulation.SimulateMsgSubmitProposal(suite.AccountKeeper, suite.BankKeeper, suite.GovKeeper, MockWeightedProposalContent{3
}.ContentSimulatorFn())

operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "")

require.NoError(t, err)

var msg v1.MsgSubmitProposal
	err = govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)

require.NoError(t, err)

require.True(t, operationMsg.OK)

require.Equal(t, "cosmos1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7u4x9a0", msg.Proposer)

require.NotEqual(t, len(msg.InitialDeposit), 0)

require.Equal(t, "2686011stake", msg.InitialDeposit[0].String())

require.Equal(t, "title-3: ZBSpYuLyYggwexjxusrBqDOTtGTOWeLrQKjLxzIivHSlcxgdXhhuTSkuxKGLwQvuyNhYFmBZHeAerqyNEUzXPFGkqEGqiQWIXnku", msg.Messages[0].GetCachedValue().(*v1.MsgExecLegacyContent).Content.GetCachedValue().(v1beta1.Content).GetTitle())

require.Equal(t, "description-3: NJWzHdBNpAXKJPHWQdrGYcAHSctgVlqwqHoLfHsXUdStwfefwzqLuKEhmMyYLdbZrcPgYqjNHxPexsruwEGStAneKbWkQDDIlCWBLSiAASNhZqNFlPtfqPJoxKsgMdzjWqLWdqKQuJqWPMvwPQWZUtVMOTMYKJbfdlZsjdsomuScvDmbDkgRualsxDvRJuCAmPOXitIbcyWsKGSdrEunFAOdmXnsuyFVgJqEjbklvmwrUlsxjRSfKZxGcpayDdgoFcnVSutxjRgOSFzPwidAjubMncNweqpbxhXGchpZUxuFDOtpnhNUycJICRYqsPhPSCjPTWZFLkstHWJxvdPEAyEIxXgLwbNOjrgzmaujiBABBIXvcXpLrbcEWNNQsbjvgJFgJkflpRohHUutvnaUqoopuKjTDaemDeSdqbnOzcfJpcTuAQtZoiLZOoAIlboFDAeGmSNwkvObPRvRWQgWkGkxwtPauYgdkmypLjbqhlHJIQTntgWjXwZdOyYEdQRRLfMSdnxqppqUofqLbLQDUjwKVKfZJUJQPsWIPwIVaSTrmKskoAhvmZyJgeRpkaTfGgrJzAigcxtfshmiDCFkuiluqtMOkidknnTBtumyJYlIsWLnCQclqdVmikUoMOPdPWwYbJxXyqUVicNxFxyqJTenNblyyKSdlCbiXxUiYUiMwXZASYfvMDPFgxniSjWaZTjHkqlJvtBsXqwPpyVxnJVGFWhfSxgOcduoxkiopJvFjMmFabrGYeVtTXLhxVUEiGwYUvndjFGzDVntUvibiyZhfMQdMhgsiuysLMiePBNXifRLMsSmXPkwlPloUbJveCvUlaalhZHuvdkCnkSHbMbmOnrfEGPwQiACiPlnihiaOdbjPqPiTXaHDoJXjSlZmltGqNHHNrcKdlFSCdmVOuvDcBLdSklyGJmcLTbSFtALdGlPkqqecJrpLCXNPWefoTJNgEJlyMEPneVaxxduAAEqQpHWZodWyRkDAxzyMnFMcjSVqeRXLqsNyNtQBbuRvunZflWSbbvXXdkyLikYqutQhLPONXbvhcQZJPSWnOulqQaXmbfFxAkqfYeseSHOQidHwbcsOaMnSrrmGjjRmEMQNuknupMxJiIeVjmgZvbmjPIQTEhQFULQLBMPrxcFPvBinaOPYWGvYGRKxLZdwamfRQQFngcdSlvwjfaPbURasIsGJVHtcEAxnIIrhSriiXLOlbEBLXFElXJFGxHJczRBIxAuPKtBisjKBwfzZFagdNmjdwIRvwzLkFKWRTDPxJCmpzHUcrPiiXXHnOIlqNVoGSXZewdnCRhuxeYGPVTfrNTQNOxZmxInOazUYNTNDgzsxlgiVEHPKMfbesvPHUqpNkUqbzeuzfdrsuLDpKHMUbBMKczKKWOdYoIXoPYtEjfOnlQLoGnbQUCuERdEFaptwnsHzTJDsuZkKtzMpFaZobynZdzNydEeJJHDYaQcwUxcqvwfWwNUsCiLvkZQiSfzAHftYgAmVsXgtmcYgTqJIawstRYJrZdSxlfRiqTufgEQVambeZZmaAyRQbcmdjVUZZCgqDrSeltJGXPMgZnGDZqISrGDOClxXCxMjmKqEPwKHoOfOeyGmqWqihqjINXLqnyTesZePQRqaWDQNqpLgNrAUKulklmckTijUltQKuWQDwpLmDyxLppPVMwsmBIpOwQttYFMjgJQZLYFPmxWFLIeZihkRNnkzoypBICIxgEuYsVWGIGRbbxqVasYnstWomJnHwmtOhAFSpttRYYzBmyEtZXiCthvKvWszTXDbiJbGXMcrYpKAgvUVFtdKUfvdMfhAryctklUCEdjetjuGNfJjajZtvzdYaqInKtFPPLYmRaXPdQzxdSQfmZDEVHlHGEGNSPRFJuIfKLLfUmnHxHnRjmzQPNlqrXgifUdzAGKVabYqvcDeYoTYgPsBUqehrBhmQUgTvDnsdpuhUoxskDdppTsYMcnDIPSwKIqhXDCIxOuXrywahvVavvHkPuaenjLmEbMgrkrQLHEAwrhHkPRNvonNQKqprqOFVZKAtpRSpvQUxMoXCMZLSSbnLEFsjVfANdQNQVwTmGxqVjVqRuxREAhuaDrFgEZpYKhwWPEKBevBfsOIcaZKyykQafzmGPLRAKDtTcJxJVgiiuUkmyMYuDUNEUhBEdoBLJnamtLmMJQgmLiUELIhLpiEvpOXOvXCPUeldLFqkKOwfacqIaRcnnZvERKRMCKUkMABbDHytQqQblrvoxOZkwzosQfDKGtIdfcXRJNqlBNwOCWoQBcEWyqrMlYZIAXYJmLfnjoJepgSFvrgajaBAIksoyeHqgqbGvpAstMIGmIhRYGGNPRIfOQKsGoKgxtsidhTaAePRCBFqZgPDWCIkqOJezGVkjfYUCZTlInbxBXwUAVRsxHTQtJFnnpmMvXDYCVlEmnZBKhmmxQOIQzxFWpJQkQoSAYzTEiDWEOsVLNrbfzeHFRyeYATakQQWmFDLPbVMCJcWjFGJjfqCoVzlbNNEsqxdSmNPjTjHYOkuEMFLkXYGaoJlraLqayMeCsTjWNRDPBywBJLAPVkGQqTwApVVwYAetlwSbzsdHWsTwSIcctkyKDuRWYDQikRqsKTMJchrliONJeaZIzwPQrNbTwxsGdwuduvibtYndRwpdsvyCktRHFalvUuEKMqXbItfGcNGWsGzubdPMYayOUOINjpcFBeESdwpdlTYmrPsLsVDhpTzoMegKrytNVZkfJRPuDCUXxSlSthOohmsuxmIZUedzxKmowKOdXTMcEtdpHaPWgIsIjrViKrQOCONlSuazmLuCUjLltOGXeNgJKedTVrrVCpWYWHyVrdXpKgNaMJVjbXxnVMSChdWKuZdqpisvrkBJPoURDYxWOtpjzZoOpWzyUuYNhCzRoHsMjmmWDcXzQiHIyjwdhPNwiPqFxeUfMVFQGImhykFgMIlQEoZCaRoqSBXTSWAeDumdbsOGtATwEdZlLfoBKiTvodQBGOEcuATWXfiinSjPmJKcWgQrTVYVrwlyMWhxqNbCMpIQNoSMGTiWfPTCezUjYcdWppnsYJihLQCqbNLRGgqrwHuIvsazapTpoPZIyZyeeSueJuTIhpHMEJfJpScshJubJGfkusuVBgfTWQoywSSliQQSfbvaHKiLnyjdSbpMkdBgXepoSsHnCQaYuHQqZsoEOmJCiuQUpJkmfyfbIShzlZpHFmLCsbknEAkKXKfRTRnuwdBeuOGgFbJLbDksHVapaRayWzwoYBEpmrlAxrUxYMUekKbpjPNfjUCjhbdMAnJmYQVZBQZkFVweHDAlaqJjRqoQPoOMLhyvYCzqEuQsAFoxWrzRnTVjStPadhsESlERnKhpEPsfDxNvxqcOyIulaCkmPdambLHvGhTZzysvqFauEgkFRItPfvisehFmoBhQqmkfbHVsgfHXDPJVyhwPllQpuYLRYvGodxKjkarnSNgsXoKEMlaSKxKdcVgvOkuLcfLFfdtXGTclqfPOfeoVLbqcjcXCUEBgAGplrkgsmIEhWRZLlGPGCwKWRaCKMkBHTAcypUrYjWwCLtOPVygMwMANGoQwFnCqFrUGMCRZUGJKTZIGPyldsifauoMnJPLTcDHmilcmahlqOELaAUYDBuzsVywnDQfwRLGIWozYaOAilMBcObErwgTDNGWnwQMUgFFSKtPDMEoEQCTKVREqrXZSGLqwTMcxHfWotDllNkIJPMbXzjDVjPOOjCFuIvTyhXKLyhUScOXvYthRXpPfKwMhptXaxIxgqBoUqzrWbaoLTVpQoottZyPFfNOoMioXHRuFwMRYUiKvcWPkrayyTLOCFJlAyslDameIuqVAuxErqFPEWIScKpBORIuZqoXlZuTvAjEdlEWDODFRregDTqGNoFBIHxvimmIZwLfFyKUfEWAnNBdtdzDmTPXtpHRGdIbuucfTjOygZsTxPjfweXhSUkMhPjMaxKlMIJMOXcnQfyzeOcbWwNbeH", msg.Messages[0].GetCachedValue().(*v1.MsgExecLegacyContent).Content.GetCachedValue().(v1beta1.Content).GetDescription())

require.Equal(t, "gov", msg.Route())

require.Equal(t, simulation.TypeMsgSubmitProposal, msg.Type())
}

/ TestSimulateMsgDeposit tests the normal scenario of a valid message of type TypeMsgDeposit.
/ Abnormal scenarios, where errors occur, are not tested here.
func TestSimulateMsgDeposit(t *testing.T) {
    suite, ctx := createTestSuite(t, false)
    app := suite.App
    blockTime := time.Now().UTC()

ctx = ctx.WithBlockTime(blockTime)

	/ setup 3 accounts
    s := rand.NewSource(1)
    r := rand.New(s)
    accounts := getTestingAccounts(t, r, suite.AccountKeeper, suite.BankKeeper, suite.StakingKeeper, ctx, 3)

	/ setup a proposal
    content := v1beta1.NewTextProposal("Test", "description")

contentMsg, err := v1.NewLegacyContent(content, suite.GovKeeper.GetGovernanceAccount(ctx).GetAddress().String())

require.NoError(t, err)
    submitTime := ctx.BlockHeader().Time
    depositPeriod := suite.GovKeeper.GetParams(ctx).MaxDepositPeriod

	proposal, err := v1.NewProposal([]sdk.Msg{
    contentMsg
}, 1, "", submitTime, submitTime.Add(*depositPeriod), "text proposal", "description", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)

suite.GovKeeper.SetProposal(ctx, proposal)

	/ begin a new block
	app.BeginBlock(abci.RequestBeginBlock{
    Header: tmproto.Header{
    Height: app.LastBlockHeight() + 1,
    AppHash: app.LastCommitID().Hash,
    Time: blockTime
}})

	/ execute operation
    op := simulation.SimulateMsgDeposit(suite.AccountKeeper, suite.BankKeeper, suite.GovKeeper)

operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "")

require.NoError(t, err)

var msg v1.MsgDeposit
	err = govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)

require.NoError(t, err)

require.True(t, operationMsg.OK)

require.Equal(t, uint64(1), msg.ProposalId)

require.Equal(t, "cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r", msg.Depositor)

require.NotEqual(t, len(msg.Amount), 0)

require.Equal(t, "560969stake", msg.Amount[0].String())

require.Equal(t, "gov", msg.Route())

require.Equal(t, simulation.TypeMsgDeposit, msg.Type())
}

/ TestSimulateMsgVote tests the normal scenario of a valid message of type TypeMsgVote.
/ Abnormal scenarios, where errors occur, are not tested here.
func TestSimulateMsgVote(t *testing.T) {
    suite, ctx := createTestSuite(t, false)
    app := suite.App
    blockTime := time.Now().UTC()

ctx = ctx.WithBlockTime(blockTime)

	/ setup 3 accounts
    s := rand.NewSource(1)
    r := rand.New(s)
    accounts := getTestingAccounts(t, r, suite.AccountKeeper, suite.BankKeeper, suite.StakingKeeper, ctx, 3)

	/ setup a proposal
    govAcc := suite.GovKeeper.GetGovernanceAccount(ctx).GetAddress().String()

contentMsg, err := v1.NewLegacyContent(v1beta1.NewTextProposal("Test", "description"), govAcc)

require.NoError(t, err)
    submitTime := ctx.BlockHeader().Time
    depositPeriod := suite.GovKeeper.GetParams(ctx).MaxDepositPeriod

	proposal, err := v1.NewProposal([]sdk.Msg{
    contentMsg
}, 1, "", submitTime, submitTime.Add(*depositPeriod), "text proposal", "description", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)

suite.GovKeeper.ActivateVotingPeriod(ctx, proposal)

	/ begin a new block
	app.BeginBlock(abci.RequestBeginBlock{
    Header: tmproto.Header{
    Height: app.LastBlockHeight() + 1,
    AppHash: app.LastCommitID().Hash,
    Time: blockTime
}})

	/ execute operation
    op := simulation.SimulateMsgVote(suite.AccountKeeper, suite.BankKeeper, suite.GovKeeper)

operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "")

require.NoError(t, err)

var msg v1.MsgVote
	govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)

require.True(t, operationMsg.OK)

require.Equal(t, uint64(1), msg.ProposalId)

require.Equal(t, "cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r", msg.Voter)

require.Equal(t, v1.OptionYes, msg.Option)

require.Equal(t, "gov", msg.Route())

require.Equal(t, simulation.TypeMsgVote, msg.Type())
}

/ TestSimulateMsgVoteWeighted tests the normal scenario of a valid message of type TypeMsgVoteWeighted.
/ Abnormal scenarios, where errors occur, are not tested here.
func TestSimulateMsgVoteWeighted(t *testing.T) {
    suite, ctx := createTestSuite(t, false)
    app := suite.App
    blockTime := time.Now().UTC()

ctx = ctx.WithBlockTime(blockTime)

	/ setup 3 accounts
    s := rand.NewSource(1)
    r := rand.New(s)
    accounts := getTestingAccounts(t, r, suite.AccountKeeper, suite.BankKeeper, suite.StakingKeeper, ctx, 3)

	/ setup a proposal
    govAcc := suite.GovKeeper.GetGovernanceAccount(ctx).GetAddress().String()

contentMsg, err := v1.NewLegacyContent(v1beta1.NewTextProposal("Test", "description"), govAcc)

require.NoError(t, err)
    submitTime := ctx.BlockHeader().Time
    depositPeriod := suite.GovKeeper.GetParams(ctx).MaxDepositPeriod

	proposal, err := v1.NewProposal([]sdk.Msg{
    contentMsg
}, 1, "", submitTime, submitTime.Add(*depositPeriod), "text proposal", "test", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))

require.NoError(t, err)

suite.GovKeeper.ActivateVotingPeriod(ctx, proposal)

	/ begin a new block
	app.BeginBlock(abci.RequestBeginBlock{
    Header: tmproto.Header{
    Height: app.LastBlockHeight() + 1,
    AppHash: app.LastCommitID().Hash,
    Time: blockTime
}})

	/ execute operation
    op := simulation.SimulateMsgVoteWeighted(suite.AccountKeeper, suite.BankKeeper, suite.GovKeeper)

operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "")

require.NoError(t, err)

var msg v1.MsgVoteWeighted
	govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)

require.True(t, operationMsg.OK)

require.Equal(t, uint64(1), msg.ProposalId)

require.Equal(t, "cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r", msg.Voter)

require.True(t, len(msg.Options) >= 1)

require.Equal(t, "gov", msg.Route())

require.Equal(t, simulation.TypeMsgVoteWeighted, msg.Type())
}

type suite struct {
    cdc           codec.Codec
	AccountKeeper authkeeper.AccountKeeper
	BankKeeper    bankkeeper.Keeper
	GovKeeper     *keeper.Keeper
	StakingKeeper *stakingkeeper.Keeper
	App           *runtime.App
}

/ returns context and an app with updated mint keeper
func createTestSuite(t *testing.T, isCheckTx bool) (suite, sdk.Context) {
    res := suite{
}

app, err := simtestutil.Setup(configurator.NewAppConfig(
		configurator.AuthModule(),
		configurator.TxModule(),
		configurator.ParamsModule(),
		configurator.BankModule(),
		configurator.StakingModule(),
		configurator.ConsensusModule(),
		configurator.GovModule(),
	), &res.AccountKeeper, &res.BankKeeper, &res.GovKeeper, &res.StakingKeeper, &res.cdc)

require.NoError(t, err)
    ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{
})

res.App = app
	return res, ctx
}

func getTestingAccounts(
	t *testing.T, r *rand.Rand,
	accountKeeper authkeeper.AccountKeeper, bankKeeper bankkeeper.Keeper, stakingKeeper *stakingkeeper.Keeper,
	ctx sdk.Context, n int,
) []simtypes.Account {
    accounts := simtypes.RandomAccounts(r, n)
    initAmt := stakingKeeper.TokensFromConsensusPower(ctx, 200)
    initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt))

	/ add coins to the accounts
    for _, account := range accounts {
    acc := accountKeeper.NewAccountWithAddress(ctx, account.Address)

accountKeeper.SetAccount(ctx, acc)

require.NoError(t, testutil.FundAccount(bankKeeper, ctx, account.Address, initCoins))
}

return accounts
}

End-to-end Tests

End-to-end tests are at the top of the test pyramid. They must test the whole application flow, from the user perspective (for instance, CLI tests). They are located under /tests/e2e. For that, the SDK is using simapp but you should use your own application (appd). Here are some examples:
  • SDK E2E tests: Link.
  • Cosmos Hub E2E tests: Link.
  • Osmosis E2E tests: Link.
warning The SDK is in the process of creating its E2E tests, as defined in ADR-59. This page will eventually be updated with better examples.

Learn More

Learn more about testing scope in ADR-59.