Search code examples
springpostgresqlspring-boothikaricp

Connections are not closed and piling up when running @SpringBootTest classes


We have Spring Boot integration tests, and keep writing new ones regularly. I noticed database connections have been piling up: the more tests I run, the higher the connection peak to my PostgreSQL instance.

It reached a point where there are more than 300 connections requested by Spring Boot when running all tests, and it started failing the build (our max_connection is set to 300).

After some research, it came to my understanding that connections are not being released after tests have been run, because of Spring Boot test: if context is not explicitly destroyed, connections are not closed.

I find it quite weird, but tried using @DirtiesContext to prove a point, on all of our test classes, it indeed fixed the issue in a sense that it avoided peaks (no more than 30 connections at once, not piling up to 300 like before) but since this annotation forces context recreation before each test class, the build got much slower and I find it not very satisfactory to need to recreate a Spring context every time just to make sure connections are closed properly.

Data source is a HikariDataSource, configured using a configuration class.

Another workaround I found is to change maximum pool size for Hikari. I set it to something lower than the default value of 10 (I'm not sure it's useful to reserve 10 connections for each test class).
This change effectively lowers the total number of connections when I run all tests but they are still piling up (only lower!)

I think I'm missing something, how can I ensure that connections are closed after each test class? There has to be a better way than @DirtiesContext, I just can't find it. Thanks for your help.


Solution

  • It turns out that context was recreated almost with every test class because I was extensively using @MockBean annotation in my tests. Since it affects Spring context, each @MockBean/No MockBean combination in different test classes counts as a different context, i.e.:

    • Test class 1: bean MyService is a MockBean, MyOtherService is not
    • Test class 2: bean MyService is a MockBean, MyOtherService is also a MockBean
    • Test class 3: none of these two beans is a MockBean

    In such case, a new Spring context will created for each class because the bean configuration is different, resulting in an increasing number of connections to the datasource.

    To (partially) solve this, I looked for patterns in the beans combinations of my test classes and created a new class I called TestMockBeans.

    Its sole purpose is to declare as many MockBeans and/or SpyBeans as possible to re-use in similar test configurations. I extend corresponding test classes with TestMockBeans, and then, because they share this similar setup, Spring identifies their contexts as similar and does not recreate a new one for every test class.

    As you can guess, not all of my tests throughout the Spring boot app share the same need for Mockbeans (or absence of Mockbeans) so it's only a partial solution, but I hope it will help someone experiencing the same issue to mitigate it.