I generally develop angular applications driven by tests.
That works well, but when using redux in my projects (currently ngrx, but also angular/redux), there are several different aspects to consider when testing and developing stores and feature/fractal-stores, driven by tests.
Intend
The issue is to find a good strategy to test and develop driven by tests.
There are e2e-tests, integration tests and unit tests, where last ones mostly tests static functions and static reactive variables in this context.
My main intend is to drive the development by tests from an integration level of stores and substores, down to the single components of the stores.
I want to be able to initially develop the store without integration in the rest of the angular application.
So scenarios where migrating from a non-redux data management or migrating from one redux framework to another can be done smoothly without a big bang.
Different perspectives and strategies
I tried different strategies of different perspectives.
When writing about store´s components i mean its reducers, effects, actions and action creators.
For me selectors are not parts of a store, but rather convenience functions that helps to access subsets of its state.
1. Treat the store and its components as a whole
When we treat the store´s components as just outsourced functions and variables of an holistic store, it is sufficient to test them integrated within encapsulating stores.
technical functionality of a store is specified in a whole
stores are explicitly tested as one integrated component, so their functionality is not just ensured in the e2e-tests
the direct effects and side effects of actions are specified at one single point.
encapsulation into a store is only fictive. In practice there is no explicit class for each store, there is just one big store object.
it is a very object orientated perspective in a more functional world
can lead to very comprehensive integration test suites
no „real“ unit tests
2. Treat the store´s components strictly as separate components that are tested isolated
We treat the store´s components as separate and completely independent components and test them isolated.
small, lean test suites focusing on the respective functions and reactive variables
impact of actions is specified separately to the responsibility of the different components
real unit tests
the interaction of the different components is just tested in the e2e-tests
the specification of the actions´ impact is spread into multiple test suites
the high cohesion of the store´s components is only seen in the file structure and their configuration within the ng modules
3. Treat the store´s components as separate components that are tested separate, but integrated.
We treat the store´s components as separate components, test them also separately, but integrated in stores.
small, lean tests focusing on the respective functions and reactive variables
impact of actions is specified separated to the responsibility of the different components
components of stores are tested integrated, so their functionality is not just ensured in the e2e-tests
the belonging to a specific store is also seen in the integration tests
the specification of the actions´ impact is spread into multiple specs
on first look on the spec name seems so be unit tests, but are integration tests
no „real“ unit tests
4. Treat the store and its components as a whole that is developed and tested depending on its actions
We treat the store and its components as a whole, develop and test them driven by its actions.
This perspective is similar to the first one, but orientates a bit more at the core concept and idea of Redux and also enables a better substructuring.
The thought is that in Redux and its stores is all about actions.
Actions are fired to change data and to trigger side effects which in turn trigger services. All the behavior is driven by actions.
So in this approach the tests are structured depending on the actions. Whereby the actions are tested integrated in the store.
In more complex stores, actions should be grouped to different kinds of actions and there should be one test suite for each group.
Tests of actions with simple behavior, such as only manipulating the state, can be specified directly on the top level of the test suite.
Tests of actions that leads to some more complex behavior should be substructured in nested test suites.
all impact of an action is specified and tested at one single point, not spread on the tests of the different technical components
technical functionality of a store is specified in a whole
stores are explicitly tested as one integrated component, so their functionality is not just ensured in the e2e-tests
no „real“ unit tests
Conclusion
First i started with a mix of the first and second approach, but soon the redundancy between the store´s integration test and the tests of its single components led me to hold on and to rethink about my perspective and this approach.
My second thought was to treat the components of the stores as just outsourced functions and reactive variables and to only test them encapsulated in the integration tests anymore.
Not to unit test the stores´ components still felt a bit uncommon, but the test driven development of the redux store now felt really good.
Furthermore because of structuring the tests in nested suits for every action, the output of the tests was also really nice. I saw at a glance what effects and side effects every action triggers.
But at least when i extended the store with multiple different kinds of side effects the integration test became much to big.
The second approach i just evaluated in theory, because for TDD i missed the integration test and also this would end up in a big bang, especially in the migration scenarios.
For some time the third approach felt as a good compromise and i think it is a good approach, but it still bothered me that the behavior of an action is spread on the different tests of the store´s components.
The test driven development and readability of the tests still did not feel fluent and continuous.
So finally i ended up with the last approach, where the development is driven by the actions and tests a structured depending on them. In Redux all is about the actions and in this approach the tests are too.
I would be very glad to read about your opinions and approaches to this issue.