@TestConfiguration bean override not working on Spring Boot 2.4.0

87 Views Asked by At

There is a very similar issue to mine here: Spring Boot: @TestConfiguration Not Overriding Bean During Integration Test

But I think I already applied every fix from this linked thread, and my weird issue is, that locally my integration tests run, this issue only occurs in my GitLab pipeline.

I have a SpringBootTest integration test, with full application context loading. I have the following property overridden, in the following way:

@SpringBootTest({"spring.main.allow-bean-definition-overriding=true"})

And I have a static nested class inside the test class, that overrides the beans I want to override:

@TestConfiguration
public static class DifferentClassNameThanTheConfigClass {

  @Bean
  @Primary
  public ClientToBeMocked differentMethodNameThanInConfligClass() {
    return new ClientToBeMocked(mockitoMock);
  }
}

And finally this TestConfiguration is imported with the following annotation on top of the test class:

@Import(TestClassName.DifferentClassNameThanTheConfigClass.class)

And from GitLab job execution logs I clearly see the bean override is not working because the test is trying to connect to an AKV keyvault with a UAMI that is not tied to the VM hosting the GitLab runner.

My question is, how is it possible, that the bean replacement is not picked up by the test? In the original Configuration class the AKV lookup happens in the bean definition method, so my alternative would be to not mock the internal dependency of the client class, but mock the whole client class instead. But I would like to understand what is the issue here.

2

There are 2 best solutions below

0
J-J On

You can use org.springframework.test.context.ActiveProfiles along with @TestConfiguration and load that profile for a Test.

So it becomes something like below.

@SpringBootTest
@ActiveProfiles("MyTestProfile")
class MyTest {

    @TestConfiguration
    @Profile("MyTestProfile")
    public static class DifferentClassNameThanTheConfigClass {
        @Bean
        @Primary
        public ClientToBeMocked differentMethodNameThanInConfligClass() {
            return mock(ClientToBeMocked.class);
        }
    }
}
0
logi0517 On

The problem was not with test bean not being picked up, but that the production bean was also initialized, the @TestConfiguration is not used to replace bean definition, this is explained by Phill Webb here as well: stackoverflow.com/a/77205870/5027640

In my testing environment, calling the production bean definition meant an exception was thrown, so I made sure to use MockBean instead, and mocked the ClientToBeMocked class instead.

Of course using Profiles would also have been an option, but I wanted to use an approach that does not modify application code for the sake of testing configuration.