The Composable Architecture — The confusion between unit test and integration test
Testing in the Composable Architecture (TCA) is very simple and convenient because this framework simply does almost everything. However, sometimes this convenience makes developers easy to confuse between the unit tests and integration tests. In this article, I am going to shed some light on what this problem exactly is, why it occurs, and the logical thinking when writing tests.
Types of tests in TCA
If you’ve ever used TCA, you will find that in this architecture, there are two main concerns:
- Business logic in the reducer
- View states
From that, with testing, we also need to have two types of testing: the Business Logic Test and the View States Test. Let me show an example in my codebase
Please note that these are all within the scope of the unit test. I know each team, each person will have their own definition of how is called a unit test. So for me, when using TCA, each scope should be independently tested and considered as a unit. See the following example:
Each scope such as Sign Up/ Log In/ Home is seen as each unit. TCA has enough capabilities to help us separate the units out and EASILY COMPOSE them back together. That’s why it gets called composable architecture. Therefore, with the unit test, we will internally test the sign-up section, for example.
After testing carefully each unit, the next part will be integration tests. For example, after signing up successfully, which the next screen is. It might be the Home screen or might be Introduction screen, so on. Because it totally depends on the business logic code, I usually have an own file for integration tests, like this
The confusion in practices
Although I have learned a bit of experience and thoroughly analyzed it myself, I still sometimes get confused between unit tests and integration tests. Why is this happening? This comes from the nature of the testing framework that TCA offers. Whether you are in unit tests or integration tests, individual test cases, or combine scopes, screens together, you must need to start from the starting point.
For example, here is an expected flow:
- Tap login button -> Fire a request -> Receive the response -> If success -> Move to next screen
Then obviously we need to start from the first step .send(tapOnLoginButton) ✅. It is not possible to start sending at some point in the middle of the road, for example, .send(receiveResponse) ❌. Therefore, during the process, you will feel that there are steps that are duplicated. So to avoid that, in the integration test section, what you need is to prepare the most ideal conditions for getting the expected output, (like stubbing a success response), to test whether in this case, does it work as you want? (navigate to the next expected screen or show something off, so on).
Maybe after reading this article, you will feel everything clear and easy to understand. Me too, but before that, it took me many refactors to realize these. So I want to write this down to help you save more time when you first start using TCA (and for me).
Again, hope you love this article and share it with your friends. I always open to discuss more this architecture. See you in the next article.