github.com/cosmos/cosmos-sdk@v0.50.10/docs/architecture/adr-059-test-scopes.md (about)

     1  # ADR 059: Test Scopes
     2  
     3  ## Changelog
     4  
     5  * 2022-08-02: Initial Draft
     6  * 2023-03-02: Add precision for integration tests
     7  * 2023-03-23: Add precision for E2E tests
     8  
     9  ## Status
    10  
    11  PROPOSED Partially Implemented
    12  
    13  ## Abstract
    14  
    15  Recent work in the SDK aimed at breaking apart the monolithic root go module has highlighted
    16  shortcomings and inconsistencies in our testing paradigm. This ADR clarifies a common
    17  language for talking about test scopes and proposes an ideal state of tests at each scope.
    18  
    19  ## Context
    20  
    21  [ADR-053: Go Module Refactoring](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-053-go-module-refactoring.md) expresses our desire for an SDK composed of many
    22  independently versioned Go modules, and [ADR-057: App Wiring](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-057-app-wiring.md) offers a methodology
    23  for breaking apart inter-module dependencies through the use of dependency injection. As
    24  described in [EPIC: Separate all SDK modules into standalone go modules](https://github.com/cosmos/cosmos-sdk/issues/11899), module
    25  dependencies are particularly complected in the test phase, where simapp is used as
    26  the key test fixture in setting up and running tests. It is clear that the successful
    27  completion of Phases 3 and 4 in that EPIC require the resolution of this dependency problem.
    28  
    29  In [EPIC: Unit Testing of Modules via Mocks](https://github.com/cosmos/cosmos-sdk/issues/12398) it was thought this Gordian knot could be
    30  unwound by mocking all dependencies in the test phase for each module, but seeing how these
    31  refactors were complete rewrites of test suites discussions began around the fate of the
    32  existing integration tests. One perspective is that they ought to be thrown out, another is
    33  that integration tests have some utility of their own and a place in the SDK's testing story.
    34  
    35  Another point of confusion has been the current state of CLI test suites, [x/auth](https://github.com/cosmos/cosmos-sdk/blob/0f7e56c6f9102cda0ca9aba5b6f091dbca976b5a/x/auth/client/testutil/suite.go#L44-L49) for
    36  example. In code these are called integration tests, but in reality function as end to end
    37  tests by starting up a tendermint node and full application. [EPIC: Rewrite and simplify
    38  CLI tests](https://github.com/cosmos/cosmos-sdk/issues/12696) identifies the ideal state of CLI tests using mocks, but does not address the
    39  place end to end tests may have in the SDK.
    40  
    41  From here we identify three scopes of testing, **unit**, **integration**, **e2e** (end to
    42  end), seek to define the boundaries of each, their shortcomings (real and imposed), and their
    43  ideal state in the SDK.
    44  
    45  ### Unit tests
    46  
    47  Unit tests exercise the code contained in a single module (e.g. `/x/bank`) or package
    48  (e.g. `/client`) in isolation from the rest of the code base. Within this we identify two
    49  levels of unit tests, *illustrative* and *journey*. The definitions below lean heavily on
    50  [The BDD Books - Formulation](https://leanpub.com/bddbooks-formulation) section 1.3.
    51  
    52  *Illustrative* tests exercise an atomic part of a module in isolation - in this case we
    53  might do fixture setup/mocking of other parts of the module.
    54  
    55  Tests which exercise a whole module's function with dependencies mocked, are *journeys*.
    56  These are almost like integration tests in that they exercise many things together but still
    57  use mocks.
    58  
    59  Example 1 journey vs illustrative tests - [depinject's BDD style tests](https://github.com/cosmos/cosmos-sdk/blob/main/depinject/features/bindings.feature), show how we can
    60  rapidly build up many illustrative cases demonstrating behavioral rules without [very much code](https://github.com/cosmos/cosmos-sdk/blob/main/depinject/binding_test.go) while maintaining high level readability.
    61  
    62  Example 2 [depinject table driven tests](https://github.com/cosmos/cosmos-sdk/blob/main/depinject/provider_desc_test.go)
    63  
    64  Example 3 [Bank keeper tests](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/x/bank/keeper/keeper_test.go#L94-L105) - A mock implementation of `AccountKeeper` is supplied to the keeper constructor.
    65  
    66  #### Limitations
    67  
    68  Certain modules are tightly coupled beyond the test phase. A recent dependency report for
    69  `bank -> auth` found 274 total usages of `auth` in `bank`, 50 of which are in
    70  production code and 224 in test. This tight coupling may suggest that either the modules
    71  should be merged, or refactoring is required to abstract references to the core types tying
    72  the modules together. It could also indicate that these modules should be tested together
    73  in integration tests beyond mocked unit tests.
    74  
    75  In some cases setting up a test case for a module with many mocked dependencies can be quite
    76  cumbersome and the resulting test may only show that the mocking framework works as expected
    77  rather than working as a functional test of interdependent module behavior.
    78  
    79  ### Integration tests
    80  
    81  Integration tests define and exercise relationships between an arbitrary number of modules
    82  and/or application subsystems.
    83  
    84  Wiring for integration tests is provided by `depinject` and some [helper code](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/testutil/sims/app_helpers.go#L95) starts up
    85  a running application. A section of the running application may then be tested. Certain
    86  inputs during different phases of the application life cycle are expected to produce
    87  invariant outputs without too much concern for component internals. This type of black box
    88  testing has a larger scope than unit testing.
    89  
    90  Example 1 [client/grpc_query_test/TestGRPCQuery](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/client/grpc_query_test.go#L111-L129) - This test is misplaced in `/client`,
    91  but tests the life cycle of (at least) `runtime` and `bank` as they progress through
    92  startup, genesis and query time. It also exercises the fitness of the client and query
    93  server without putting bytes on the wire through the use of [QueryServiceTestHelper](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/baseapp/grpcrouter_helpers.go#L31).
    94  
    95  Example 2 `x/evidence` Keeper integration tests - Starts up an application composed of [8
    96  modules](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/x/evidence/testutil/app.yaml#L1) with [5 keepers](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/x/evidence/keeper/keeper_test.go#L101-L106) used in the integration test suite. One test in the suite
    97  exercises [HandleEquivocationEvidence](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/x/evidence/keeper/infraction_test.go#L42) which contains many interactions with the staking
    98  keeper.
    99  
   100  Example 3 - Integration suite app configurations may also be specified via golang (not
   101  YAML as above) [statically](https://github.com/cosmos/cosmos-sdk/blob/main/x/nft/testutil/app_config.go) or [dynamically](https://github.com/cosmos/cosmos-sdk/blob/8c23f6f957d1c0bedd314806d1ac65bea59b084c/tests/integration/bank/keeper/keeper_test.go#L129-L134).
   102  
   103  #### Limitations
   104  
   105  Setting up a particular input state may be more challenging since the application is
   106  starting from a zero state. Some of this may be addressed by good test fixture
   107  abstractions with testing of their own. Tests may also be more brittle, and larger
   108  refactors could impact application initialization in unexpected ways with harder to
   109  understand errors. This could also be seen as a benefit, and indeed the SDK's current
   110  integration tests were helpful in tracking down logic errors during earlier stages
   111  of app-wiring refactors.
   112  
   113  ### Simulations
   114  
   115  Simulations (also called generative testing) are a special case of integration tests where
   116  deterministically random module operations are executed against a running simapp, building
   117  blocks on the chain until a specified height is reached. No *specific* assertions are
   118  made for the state transitions resulting from module operations but any error will halt and
   119  fail the simulation. Since `crisis` is included in simapp and the simulation runs
   120  EndBlockers at the end of each block any module invariant violations will also fail
   121  the simulation.
   122  
   123  Modules must implement [AppModuleSimulation.WeightedOperations](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/types/module/simulation.go#L31) to define their
   124  simulation operations. Note that not all modules implement this which may indicate a
   125  gap in current simulation test coverage.
   126  
   127  Modules not returning simulation operations:
   128  
   129  * `auth`
   130  * `evidence`
   131  * `mint`
   132  * `params`
   133  
   134  A separate binary, [runsim](https://github.com/cosmos/tools/tree/master/cmd/runsim), is responsible for kicking off some of these tests and
   135  managing their life cycle.
   136  
   137  #### Limitations
   138  
   139  * [A success](https://github.com/cosmos/cosmos-sdk/runs/7606931983?check_suite_focus=true) may take a long time to run, 7-10 minutes per simulation in CI.
   140  * [Timeouts](https://github.com/cosmos/cosmos-sdk/runs/7606932295?check_suite_focus=true) sometimes occur on apparent successes without any indication why.
   141  * Useful error messages not provided on [failure](https://github.com/cosmos/cosmos-sdk/runs/7606932548?check_suite_focus=true) from CI, requiring a developer to run
   142    the simulation locally to reproduce.
   143  
   144  ### E2E tests
   145  
   146  End to end tests exercise the entire system as we understand it in as close an approximation
   147  to a production environment as is practical. Presently these tests are located at
   148  [tests/e2e](https://github.com/cosmos/cosmos-sdk/tree/main/tests/e2e) and rely on [testutil/network](https://github.com/cosmos/cosmos-sdk/tree/main/testutil/network) to start up an in-process Tendermint node.
   149  
   150  An application should be built as minimally as possible to exercise the desired functionality.
   151  The SDK uses an application will only the required modules for the tests. The application developer is adviced to use its own application for e2e tests.
   152  
   153  #### Limitations
   154  
   155  In general the limitations of end to end tests are orchestration and compute cost.
   156  Scaffolding is required to start up and run a prod-like environment and the this
   157  process takes much longer to start and run than unit or integration tests.
   158  
   159  Global locks present in Tendermint code cause stateful starting/stopping to sometimes hang
   160  or fail intermittently when run in a CI environment.
   161  
   162  The scope of e2e tests has been complected with command line interface testing.
   163  
   164  ## Decision
   165  
   166  We accept these test scopes and identify the following decisions points for each.
   167  
   168  | Scope       | App Type            | Mocks? |
   169  | ----------- | ------------------- | ------ |
   170  | Unit        | None                | Yes    |
   171  | Integration | integration helpers | Some   |
   172  | Simulation  | minimal app         | No     |
   173  | E2E         | minimal app         | No     |
   174  
   175  The decision above is valid for the SDK. An application developer should test their application with their full application instead of the minimal app.
   176  
   177  ### Unit Tests
   178  
   179  All modules must have mocked unit test coverage.
   180  
   181  Illustrative tests should outnumber journeys in unit tests.
   182  
   183  Unit tests should outnumber integration tests.
   184  
   185  Unit tests must not introduce additional dependencies beyond those already present in
   186  production code.
   187  
   188  When module unit test introduction as per [EPIC: Unit testing of modules via mocks](https://github.com/cosmos/cosmos-sdk/issues/12398)
   189  results in a near complete rewrite of an integration test suite the test suite should be
   190  retained and moved to `/tests/integration`. We accept the resulting test logic
   191  duplication but recommend improving the unit test suite through the addition of
   192  illustrative tests.
   193  
   194  ### Integration Tests
   195  
   196  All integration tests shall be located in `/tests/integration`, even those which do not
   197  introduce extra module dependencies.
   198  
   199  To help limit scope and complexity, it is recommended to use the smallest possible number of
   200  modules in application startup, i.e. don't depend on simapp.
   201  
   202  Integration tests should outnumber e2e tests.
   203  
   204  ### Simulations
   205  
   206  Simulations shall use a minimal application (usually via app wiring). They are located under `/x/{moduleName}/simulation`.
   207  
   208  ### E2E Tests
   209  
   210  Existing e2e tests shall be migrated to integration tests by removing the dependency on the
   211  test network and in-process Tendermint node to ensure we do not lose test coverage.
   212  
   213  The e2e rest runner shall transition from in process Tendermint to a runner powered by
   214  Docker via [dockertest](https://github.com/ory/dockertest).
   215  
   216  E2E tests exercising a full network upgrade shall be written.
   217  
   218  The CLI testing aspect of existing e2e tests shall be rewritten using the network mocking
   219  demonstrated in [PR#12706](https://github.com/cosmos/cosmos-sdk/pull/12706).
   220  
   221  ## Consequences
   222  
   223  ### Positive
   224  
   225  * test coverage is increased
   226  * test organization is improved
   227  * reduced dependency graph size in modules
   228  * simapp removed as a dependency from modules
   229  * inter-module dependencies introduced in test code are removed
   230  * reduced CI run time after transitioning away from in process Tendermint
   231  
   232  ### Negative
   233  
   234  * some test logic duplication between unit and integration tests during transition
   235  * test written using dockertest DX may be a bit worse
   236  
   237  ### Neutral
   238  
   239  * some discovery required for e2e transition to dockertest
   240  
   241  ## Further Discussions
   242  
   243  It may be useful if test suites could be run in integration mode (with mocked tendermint) or
   244  with e2e fixtures (with real tendermint and many nodes). Integration fixtures could be used
   245  for quicker runs, e2e fixures could be used for more battle hardening.
   246  
   247  A PoC `x/gov` was completed in PR [#12847](https://github.com/cosmos/cosmos-sdk/pull/12847)
   248  is in progress for unit tests demonstrating BDD [Rejected].
   249  Observing that a strength of BDD specifications is their readability, and a con is the
   250  cognitive load while writing and maintaining, current consensus is to reserve BDD use
   251  for places in the SDK where complex rules and module interactions are demonstrated.
   252  More straightforward or low level test cases will continue to rely on go table tests.
   253  
   254  Levels are network mocking in integration and e2e tests are still being worked on and formalized.