Search code examples
spring-booth2spring-boot-testcompletable-futuremockmvc

Strange issue with integration test


  1. @Sql at tested class
INSERT INTO bankdemo.bills(id, is_active, balance, currency, account_id)
VALUES('0', '1', '0.00', 'RUB', '0');
  1. green test shows that Bill with id == 0 presents in DB
    @Test
    void can_change_bill_status() throws Exception {
        
        mockMVC.perform(get("/bills/status/{id}", "0"))
            .andExpect(status().isOk())
            .andExpect(content().string(containsString("false")));
    }
  1. but next one suddenly fails
    @Test
    void can_export_data_2_csv_file() throws Exception {
        
        mockMVC.perform(get("/operations/print/{id}", "0"))
            .andExpect(status().isCreated())
            .andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM_VALUE));
    }

with CompletionException: EntityNotFoundException: Target bill with id: 0 not found

Inside controller's method under test of p.3 taking Bill from DB by using ThreadPoolTaskExecutor

    CompletableFuture<BillResponseDTO> futureBill = CompletableFuture.supplyAsync
            (() -> {try {return billService.getBillDTO(id);}
                    catch(EntityNotFoundException exc) {log.error(exc.getMessage(), exc);
                    throw new CompletionException(exc);}
            }, executorService);
    BillResponseDTO bill = futureBill.join();

probably this is the case but how to test this part of code properly?

The programm itself and slice @WebMvcTest using mocked access to DB are fine. Spring Boot 2.6.6

Addition:

    @Bean
    @Primary
    public Executor asyncExecutor() {
        final int cores = Runtime.getRuntime().availableProcessors();
        final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(cores);
        executor.setMaxPoolSize(cores * 2);
        executor.setQueueCapacity(cores * 10);
        executor.initialize();
        return executor;
    }

Also there is another task running async at this particular method of controller and it does not cause any problems at all:

        CompletableFuture<List<OperationResponseDTO>> futureOperations =
                CompletableFuture.supplyAsync(() -> operationService.getAll(id), executorService);

Solution

  • Ok, so the problem was not about CompletableFuture but with behave of Spring Boot tests using H2 database. SQL scripts are initializing data strangely depending at which stage they get invoked (during start-up or by @SQL above test class or method declaration).