Search code examples
springspring-boottestingjunit

Using ThreadPoolTaskExecutor bean of appconfig in test class


I'm not able to use the bean defined in app Config in Service Test class though it works fine in Service class. How do I use the bean for test? I'm able to use executors using ReflectionTestUtils in a bit different way but not like this using beans.

My app config looks like this -

@Configuration
@EnableAsync
@EnableScheduling
public class ApplicationConfiguration {

 @Bean(name = "executor")
  public ThreadPoolTaskExecutor executor(
      @Value("${thread-pool.size}") int size,
      @Value("${thread-pool.shutdownTime}") int shutdownTime) {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(size);
    executor.setMaxPoolSize(size);
    executor.setAwaitTerminationSeconds(shutdownTime);

    executor.initialize();
    return executor;
  }
  
}

Service -

public class RandomService {

private ThreadPoolTaskExecutor executor;

public RandomService(@Qualifier("executor") ThreadPoolTaskExecutor executor) {
this.executor = executor;
}

public CompletableFuture<Void> getInfo(DataRequest request) {
return CompletableFuture.runAsync(
            () -> {
              DataResponse dataResponse =
                  getProcessedData(request);
            }, executor)
        .exceptionally(
            ex -> {
             log.error("Exception occurred :: ", ex);
            });
}

}

Test -

@RunWith(MockitoJUnitRunner.class)
public class randomServiceTest {
@InjectMocks private RandomService randomService;
private ThreadPoolTaskExecutor executor; // How to use the bean defined in appconfig with all values in Test? 

@Before
  public void setUp() throws Exception {
    randomService = new RandomService(executor);
    executor.setCorePoolSize(10); // executor is null here
  }
@Test
  public void testgetInfo() throws Exception {
    randomService.getInfo(request);
  }
}

[Update] - @Ken Chan's answer did help. I do have some other mocks just that I included only code which is of interest earlier. Now I'm trying to use another existing (in codebase) TestConfiguration class like below -

@Configuration
@Profile("test")
public class TestConfiguration {

@Bean(name = "executor")
    public ThreadPoolTaskExecutor executor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setAwaitTerminationSeconds(50);
        executor.initialize();
        return executor;
    }
}

I'm trying to load this bean into the spring context in test class using spring test support like below but all mocks and the executor bean from test config are null, not able to inject properly -

@SpringBootTest
@ExtendWith(SpringExtension.class)
@Slf4j
@ContextConfiguration(classes = TestConfiguration.class)
@ActiveProfiles("test")
public class RandomServiceTest {
@InjectMocks private RandomService randomService;
@MockBean private SomeService someService; //Tried @Mock of Mockito, but it's null
@Autowired private ThreadPoolTaskExecutor executor; // null
@Before
  public void setUp() throws Exception {
    randomService = new RandomService(someService, executor);
  }
}

Can anyone please point the issue here ?


Solution

  • If you just want to write the plain Junit test without starting the spring context , you can simply create a ApplicationConfiguration and call the executor() to create the ThreadPoolTaskExecutor instance manually like :

    public class randomServiceTest {
    
     private RandomService randomService;
     private ThreadPoolTaskExecutor executor; 
    
      @Before
      public void setUp() throws Exception {
         ApplicationConfiguration appConfig = new ApplicationConfiguration();
         var executor = appConfig.executor(10,10);
         randomService = new RandomService(executor);
      }
    
    }
    
    

    Also as you do not create any @Mock , it does not make sense to use @InjectMocks as no @Mock to inject here. Just simply wire up all the things to keep it simple.