Sasha Shpota
Sasha Shpota

Reputation: 10300

Spring Boot: How to inject the same instance of a prototype scoped bean into a Spring Boot Test?

I have a service class that uses a prototype scoped bean declared in the following way:

@Bean
@Scope(scopeName = SCOPE_PROTOTYPE, proxyMode = TARGET_CLASS)
MyBean myBean() {...}

And I have an integration test which looks like this:

@SpringBootTest
@ExtendWith(SpringExtension.class)
class MyServiceTest {
    @Autowired
    MyBean myBean;
    // tests follow here
}

Problem: I need exactly the same instance of MyBean in the test but Spring injects a different instance because the scope of the bean is 'prototype'.

Question: How to inject the same instance of a prototype scoped bean into a test?

Note: I cannot change the scope declaration of the bean.

Upvotes: 1

Views: 1580

Answers (2)

Toerktumlare
Toerktumlare

Reputation: 14772

If you cannot change anything and you insist on injecting the bean straight off then it is impossible.

The documentation clearly states:

The non-singleton prototype scope of bean deployment results in the creation of a new bean instance every time a request for that specific bean is made. That is, the bean is injected into another bean or you request it through a getBean() method call on the container. As a rule, you should use the prototype scope for all stateful beans and the singleton scope for stateless beans.

You are injecting it into another bean.

Prototype scoped beans

Upvotes: 0

davidxxx
davidxxx

Reputation: 131396

You have two approaches.

Override MyBean to make it a singleton bean :

@TestConfiguration
public class OverrideBeanConfigurationForTest {

    @Bean
    @Scope(scopeName = SCOPE_SINGLETON)
    MyBean myBean() {...}
}    

Or override it to return always the same bean :

@TestConfiguration
public class OverrideBeanConfigurationForTest {

    MyBean myBean;

    @Bean
    @Scope(scopeName = SCOPE_PROTOTYPE, proxyMode = TARGET_CLASS)
    MyBean myBean() {
      if (myBean == null){ 
         myBean = new MyBean(...),
      }
      return myBean;
    }
}    

Now import this configuration in your spring boot test and also specify the property spring.main.allow-bean-definition-overriding=true as that is false by default :

@SpringBootTest({"spring.main.allow-bean-definition-overriding=true"})
@ExtendWith(SpringExtension.class)
@Import(OverrideBeanConfigurationForTest.class)
class MyServiceTest {
    @Autowired
    MyBean myBean;
    // tests follow here
}

Tested and works.

Upvotes: 2

Related Questions