top of page

Spring integration testing I: Introduction to series

  • Cyril Sahula
  • Jan 13, 2023
  • 4 min read


Over the past few projects, I have improved the testing approach for integration testing in the Spring framework (i.e. IT). The Spring framework provides a big library, I recommend reading the documentation. In this series of articles, I would like to present how I solve integration testing which in the end leads to a well-tested application in a couple of minutes. I will demonstrate this by code in my GitHub project. When we speak about IT in the Spring application, we speak about a test that starts an application’s context and enables us to test against the running application locally or in the CI pipeline. How to implement IT in a project differs from a case by case although some statements are very common.


Most of my readers are no doubt convinced about the benefits of reasonable unit testing and integration testing and should be familiar with the testing pyramid, therefore this series is going to focus on concrete problems of integration testing rather than theory. All of the following articles will be mostly practical. I would like to briefly summarize a couple of points that IT brings or what I consider as good practice:


Stability alias peaceful sleeping

The current business has bigger requirements on flexibility, shorter time-to-market period, no outage releasing, etc. In such a world, good automatic testing is a must-have feature. When a team experiences too many bugs or releasing becomes something scary then it points to a weaker QA automatization. The integration testing is part of CI/CD pipelines andits success must be part of any feature delivery and release. In the release process, the team can then focus on new features and their quality and rely on integration tests that cover their back.


Functional requirements coverage

The definition of “done” in current enterprise software development means that a developerdelivers a feature to staging or the production environment (depending on the release process), the code is checked by a team during a code review, and the feature's acceptance criteria are covered by automatic testing (unit, integration, end2end). In back-end development, it is easy to cover most of the functional requirements by IT cheaply. No integration testing for a new API or feature must raise the question: Why?


More mocking = worse testing

Some developers told me that writing test cases is twice more work, of course, more code is written but more time is saved and the application quality is higher. They should see when a developer mainly writes unit tests in an application framework like Spring and use a lot of mocking then it is right hell. My helper rule is: do I have to refactor test cases when I refactor a code? If not then it is definitely a better testing approach. Mocks in unit tests are tight up with implementation and refactoring of implementation forces us to refactor mocking on theend such tests do not help us to validate our refactoring.


Faster is better

Speed is an essential requirement. It isn't possible to say the number of seconds or minutes that a run of IT should take. It depends on the application architecture, infrastructure dependencies, test case count, and implementation of tests. The only rule is: faster is better. Each unnecessary minute is multiplied by the count of developers. The duration of IT influences the developer's local testing, CI&CD pipelines, feedback from pull request pipelines, etc. Efficient IT configuration can gain tens of hours in months.


Don't be afraid to refactor

All developers know a situation when they must refactor a code that they didn't develop, or an application is just too complex, or there is not enough time to think about everything because of hot fixing. Good integration testing really increases the confidence of developersto make a change in all parts of code.


Get more time for QA folks

Nobody likes monkey jobs, plus they are expensive and even more in distributed architectures like serverless or microservice. In a distributed environment with each new service, there is an increased complexity also for QA. Good QA folks focus on automatization the same as developers do. When a developer writes IT then he or she saves time for QA almost for free and the testing department can focus on more useful work and improving the quality of service.


It is just one layer of the pyramid

Bear in mind that integration testing is still just a layer of the testing pyramid, but my goal is to have the best possible configuration for IT in a project. The layer allows testing a service in isolation which is really important mainly in distributed development and validates a service's responsibility and business requirements easily in a couple of seconds or minutes.


Idempotent test case

The simple rule which helps to spare a part of your life is: Each integration test case must start from its clearly defined state and can't be influenced by previous or later test cases. Also, a run of a test case is idempotent and must always return the same result.


Close to the PROD environment

The rule is simple: the environment for integration testing must be as close to production as possible. Mocking of service's dependencies like config server or databases must have a reason. Of course, in microservice or serverless architecture, a service must be testable without other business services or functions/lambdas. The rule aims at infrastructure dependencies. Examples:

  • For a test run, we start independent dependencies like SQL DB, etc. in the Dockercontainer which are killed after all tests are finished.

  • Infrastructure dependencies like config servers are usually read only for testingpurposes therefore we have the config server just for testing. It is better that mockingand mocking does not bring any benefit to us


Local environment

Developers must be able to develop and maintain integration tests from their local environment. Years ago it was possible to run IT even offline because most applications weremonoliths with relational DB. Nevertheless, now we develop services for the cloud. Databases and other dependencies in the cloud don't have embedded versions (like H2 for relational databases), or docker images, and it is really expensive to mock them. Therefore, itis beneficial to use real cloud resources, even though an internet connection is necessary, but a developer must be able to run IT locally.


Conclusion

All the rules above are just recommendations and their implementation always depends on the project. There is always a tradeoff between time/money and benefits. In the end, good integration testing must bring more time to implement real business value for your customeror company. Let’s go to the first implementation model.

Comments


Commenting on this post isn't available anymore. Contact the site owner for more info.
bottom of page