Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring boot test: context loaded for every test?

In my project we have a super class for all our tests. This is the signature of that class

@RunWith(SpringRunner.class)
@SpringBootTest(value = {"management.port=0"}, classes = Application.class, webEnvironment = WebEnvironment.RANDOM_PORT)
@ActiveProfiles({"localhost", "test"})
@ContextConfiguration(classes = {Application.class, SomeConfiguration.class})
@Ignore
public abstract class AIntegrationTest {

Where Application.class is our main class, and SomeConfiguration.class it just for some @Bean and other stuff, nothing fancy.

I use gradle, and for running my tests I do:

./gradlew :my-project:test

My problems are:

  • I'm not sure if for each test the context is being initialized. But I can assure the context gets initialized multiple times. I know this by looking at the logs.
  • Since multiple contexts are initialized, it seems that contexts overlap with each other. I know this because one of the symptoms is this exception:

    Caused by: org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [org.springframework.cloud.context.environment.EnvironmentManager@36408d9e] with key 'environmentManager'; nested exception is javax.management.InstanceAlreadyExistsException: RedeemAway:name=environmentManager,type=EnvironmentManager
    
  • Even if I don't care about the multiple contexts being loaded, is my impression that when a test finishes, the next test gets a new context BEFORE the previous one is terminated. I said this because of the overlapping of the exception from above.

Since all the tests share the same JVM, when some beans get registered twice, that exception rises up. From this link:

Context caching

It is said that:

An ApplicationContext can be uniquely identified by the combination of configuration parameters that is used to load it. Consequently, the unique combination of configuration parameters is used to generate a key under which the context is cached. The TestContext framework uses the following configuration parameters to build the context cache key

I understand that, but, I'm wondering how can I achieve that? My goal is to run all my tests over the same JVM and reuse the context with every test.

EDIT on Thu Feb 22

Things I tried:

  • spring.jmx.enabled: false
  • spring.jmx.default-domain: some-value

Really disabling JMX shouldn't help since the excpetion is around the EnvironmentManager, which is from Spring Cloud.

like image 819
Perimosh Avatar asked Feb 22 '18 14:02

Perimosh


People also ask

How do you prevent spring boot application starting for each test class?

By using the WebEnvironment. RANDOM_PORT you are telling spring boot to start a server on each class instantiation. To avoid this, use a parent class that all testclasses extend from.

Can spring have multiple application contexts?

We can have multiple application contexts that share a parent-child relationship. A context hierarchy allows multiple child contexts to share beans which reside in the parent context. Each child context can override configuration inherited from the parent context.

What is SpringBootTest annotation?

The @SpringBootTest annotation tells Spring Boot to look for a main configuration class (one with @SpringBootApplication , for instance) and use that to start a Spring application context.

What is contextLoads?

Empty contextLoads() is a test to verify if the application is able to load Spring context successfully or not.


1 Answers

I found the answer to my problem. Here is well explained:

https://github.com/spring-projects/spring-boot/issues/7174

Basically, if you run a bunch of tests, as soon as one of them gets started, if it uses the annotation @MockBean it will force Spring to reload the context.

Bonus: you will see the same behavior if your test uses org.mockito.Mock.

like image 186
Perimosh Avatar answered Sep 28 '22 07:09

Perimosh