20

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.

Perimosh
  • 2,304
  • 3
  • 20
  • 38
  • 3
    The context is always cached between tests if it is the same configuration. Configuration is determined on loaded configuration files, `@MockBean` (and friends), `@TestPropertySource` and some other things. If that is what you use then you will get a new context each time. Also your base class is weird you either use `@SpringBootTest` or `@ContextConfiguration` but not both. – M. Deinum Feb 22 '18 at 14:21
  • SpringBootTest docs says you can specify a ContextConfiguration. This is from the docs: "Annotation that can be specified on a test class that runs Spring Boot based tests. Provides the following features over and above the regular Spring TestContext Framework: Uses SpringBootContextLoader as the default ContextLoader when no specific ContextConfiguration(loader=...) is defined. Automatically searches for a SpringBootConfiguration when nested @Configuration is not used, and no explicit classes are specified." – Perimosh Feb 22 '18 at 14:25
  • No it doesn't say that. Nonetheless you are duplicating configuration with this. – M. Deinum Feb 22 '18 at 14:27
  • Ok. Anyway, SpringBootTest or ContextConfiguration together is something I started to try since yesterday. Up to yesterday, I had only SpringBootTest, and the problems were exactly the same. – Perimosh Feb 22 '18 at 14:30
  • As stated there are certain things taken into account, if those apply you get a new context... If not you are doing things wrong. Next to that `@SpringBootTest` will start a full blown context, when only using `@ContextConfiguration` that won't happen (and they possibly interfere) so remove the latter. – M. Deinum Feb 22 '18 at 14:30
  • I will remove '@ContextConfiguration'. But, again, before yesterday I didn't have '@ContextConfiguration', and my problems were exactly the same. And just to clarify, I don't want a new context with every test. I want to reuse it. – Perimosh Feb 22 '18 at 14:42
  • Have you read my comments (judging from your comments you haven't). – M. Deinum Feb 22 '18 at 15:10
  • While I was typing this I was working (I'm still working). I think I misunderstood you. You say try ONLY with _@ContextConfiguration_? – Perimosh Feb 22 '18 at 16:28
  • I tried using only _@ContextConfiguration_ and the context doesn't even get loaded. I tried _@ContextConfiguration(classes = {Application.class, SomeConfiguration.class})_ and Spring doesn't load the context. Also I'm using Spring Cloud, and my config server is not being used by my test. Am I missing some classes in `classes = {}`? – Perimosh Feb 22 '18 at 18:04
  • Thanks for your help! Look at my own answer below. – Perimosh Feb 22 '18 at 20:54
  • So basically your answer is my first comment... – M. Deinum Feb 27 '18 at 07:23
  • 1
    Yes, you are correct. The problem is that I'm debugging code I don't own, and when you said about the _@MockBean_ I was told in my team that we are not using it. Later I found that link I posted below, then I did a grep searching for _@MockBean_ and realized that we are using it. Removed it, and all started to work. Put your comment as an answer and I will vote it up. That's what the answer section is for after all. – Perimosh Feb 27 '18 at 16:16

1 Answers1

18

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.

Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
Perimosh
  • 2,304
  • 3
  • 20
  • 38