Я пытаюсь протестировать многопоточный код при загрузке Spring с Mock Mvc.
Код работает, как и ожидалось, во время выполнения, но выполняется в тесте начальной загрузки. Mock Mvc Результаты теста в пустом списке.
Исходный репозиторий содержит записи, даже в конструкторе реализации Callable , но когда вызывается call (), в его репозитории нет записей.
package com.xti.service.impl;
import com.xti.domain.Car;
import com.xti.repository.CarRepository;
import com.xti.service.CarService;
import com.xti.service.dto.CarDTO;
import com.xti.service.mapper.CarMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
/**
* Service Implementation for managing {@link Car}.
*/
@Service
@Transactional
public class CarServiceImpl implements CarService {
private final Logger log = LoggerFactory.getLogger(CarServiceImpl.class);
private final CarRepository carRepository;
private final CarMapper carMapper;
public CarServiceImpl(CarRepository carRepository, CarMapper carMapper) {
this.carRepository = carRepository;
this.carMapper = carMapper;
}
/**
* Save a car.
*
* @param carDTO the entity to save.
* @return the persisted entity.
*/
@Override
public CarDTO save(CarDTO carDTO) {
log.debug("Request to save Car : {}", carDTO);
Car car = carMapper.toEntity(carDTO);
car = carRepository.save(car);
return carMapper.toDto(car);
}
/**
* Get all the cars.
*
* @return the list of entities.
*/
@Override
@Transactional(readOnly = true)
public List<CarDTO> findAll() {
log.debug("Request to get all Cars");
ExecutorService executorService = Executors.newSingleThreadExecutor();
CarTask carTask = new CarTask(carRepository);
log.info("Original findAll().size() result {}", carRepository.findAll().size());
try {
return executorService.submit(carTask).get()
.stream()
.map(carMapper::toDto)
.collect(Collectors.toCollection(LinkedList::new));
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
// TODO why does this work at Runtime but not in MockMvc test
public class CarTask implements Callable<List<Car>> {
private final CarRepository otherCarRepository;
public CarTask(CarRepository otherCarRepository) {
this.otherCarRepository = otherCarRepository;
log.info("From CarTask constructor call() findAll().size() {}", otherCarRepository.findAll().size());
}
@Override
public List<Car> call() {
log.info("From CarTask call() findAll().size() {}", otherCarRepository.findAll().size());
return otherCarRepository.findAll();
}
}
/**
* Get one car by id.
*
* @param id the id of the entity.
* @return the entity.
*/
@Override
@Transactional(readOnly = true)
public Optional<CarDTO> findOne(Long id) {
log.debug("Request to get Car : {}", id);
return carRepository.findById(id)
.map(carMapper::toDto);
}
/**
* Delete the car by id.
*
* @param id the id of the entity.
*/
@Override
public void delete(Long id) {
log.debug("Request to delete Car : {}", id);
carRepository.deleteById(id);
}
}
CarResourceIT
package com.xti.web.rest;
import com.xti.MultithreadedTestingApp;
import com.xti.domain.Car;
import com.xti.repository.CarRepository;
import com.xti.service.CarService;
import com.xti.service.dto.CarDTO;
import com.xti.service.mapper.CarMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
package com.xti.web.rest;
@SpringBootTest(classes = MultithreadedTestingApp.class)
@AutoConfigureMockMvc
@WithMockUser
public class CarResourceIT {
private static final String DEFAULT_MODEL = "AAAAAAAAAA";
private static final String UPDATED_MODEL = "BBBBBBBBBB";
@Autowired
private CarRepository carRepository;
@Autowired
private CarMapper carMapper;
@Autowired
private CarService carService;
@Autowired
private EntityManager em;
@Autowired
private MockMvc restCarMockMvc;
private Car car;
/**
* Create an entity for this test.
*
* This is a static method, as tests for other entities might also need it,
* if they test an entity which requires the current entity.
*/
public static Car createEntity(EntityManager em) {
Car car = new Car()
.model(DEFAULT_MODEL);
return car;
}
/**
* Create an updated entity for this test.
*
* This is a static method, as tests for other entities might also need it,
* if they test an entity which requires the current entity.
*/
public static Car createUpdatedEntity(EntityManager em) {
Car car = new Car()
.model(UPDATED_MODEL);
return car;
}
@BeforeEach
public void initTest() {
car = createEntity(em);
}
@Test
@Transactional
public void createCar() throws Exception {
int databaseSizeBeforeCreate = carRepository.findAll().size();
// Create the Car
CarDTO carDTO = carMapper.toDto(car);
restCarMockMvc.perform(post("/api/cars")
.contentType(MediaType.APPLICATION_JSON)
.content(TestUtil.convertObjectToJsonBytes(carDTO)))
.andExpect(status().isCreated());
// Validate the Car in the database
List<Car> carList = carRepository.findAll();
assertThat(carList).hasSize(databaseSizeBeforeCreate + 1);
Car testCar = carList.get(carList.size() - 1);
assertThat(testCar.getModel()).isEqualTo(DEFAULT_MODEL);
}
@Test
@Transactional
public void createCarWithExistingId() throws Exception {
int databaseSizeBeforeCreate = carRepository.findAll().size();
// Create the Car with an existing ID
car.setId(1L);
CarDTO carDTO = carMapper.toDto(car);
// An entity with an existing ID cannot be created, so this API call must fail
restCarMockMvc.perform(post("/api/cars")
.contentType(MediaType.APPLICATION_JSON)
.content(TestUtil.convertObjectToJsonBytes(carDTO)))
.andExpect(status().isBadRequest());
// Validate the Car in the database
List<Car> carList = carRepository.findAll();
assertThat(carList).hasSize(databaseSizeBeforeCreate);
}
@Test
@Transactional
public void getAllCars() throws Exception {
// TODO why does CarRepository not contain any Cars?
// Initialize the database
carRepository.saveAndFlush(car);
// Get all the carList
restCarMockMvc.perform(get("/api/cars?sort=id,desc"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("$.[*].id").value(hasItem(car.getId().intValue())))
.andExpect(jsonPath("$.[*].model").value(hasItem(DEFAULT_MODEL)));
}
@Test
@Transactional
public void getCar() throws Exception {
// Initialize the database
carRepository.saveAndFlush(car);
// Get the car
restCarMockMvc.perform(get("/api/cars/{id}", car.getId()))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("$.id").value(car.getId().intValue()))
.andExpect(jsonPath("$.model").value(DEFAULT_MODEL));
}
@Test
@Transactional
public void getNonExistingCar() throws Exception {
// Get the car
restCarMockMvc.perform(get("/api/cars/{id}", Long.MAX_VALUE))
.andExpect(status().isNotFound());
}
@Test
@Transactional
public void updateCar() throws Exception {
// Initialize the database
carRepository.saveAndFlush(car);
int databaseSizeBeforeUpdate = carRepository.findAll().size();
// Update the car
Car updatedCar = carRepository.findById(car.getId()).get();
// Disconnect from session so that the updates on updatedCar are not directly saved in db
em.detach(updatedCar);
updatedCar
.model(UPDATED_MODEL);
CarDTO carDTO = carMapper.toDto(updatedCar);
restCarMockMvc.perform(put("/api/cars")
.contentType(MediaType.APPLICATION_JSON)
.content(TestUtil.convertObjectToJsonBytes(carDTO)))
.andExpect(status().isOk());
// Validate the Car in the database
List<Car> carList = carRepository.findAll();
assertThat(carList).hasSize(databaseSizeBeforeUpdate);
Car testCar = carList.get(carList.size() - 1);
assertThat(testCar.getModel()).isEqualTo(UPDATED_MODEL);
}
@Test
@Transactional
public void updateNonExistingCar() throws Exception {
int databaseSizeBeforeUpdate = carRepository.findAll().size();
// Create the Car
CarDTO carDTO = carMapper.toDto(car);
// If the entity doesn't have an ID, it will throw BadRequestAlertException
restCarMockMvc.perform(put("/api/cars")
.contentType(MediaType.APPLICATION_JSON)
.content(TestUtil.convertObjectToJsonBytes(carDTO)))
.andExpect(status().isBadRequest());
// Validate the Car in the database
List<Car> carList = carRepository.findAll();
assertThat(carList).hasSize(databaseSizeBeforeUpdate);
}
@Test
@Transactional
public void deleteCar() throws Exception {
// Initialize the database
carRepository.saveAndFlush(car);
int databaseSizeBeforeDelete = carRepository.findAll().size();
// Delete the car
restCarMockMvc.perform(delete("/api/cars/{id}", car.getId())
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isNoContent());
// Validate the database contains one less item
List<Car> carList = carRepository.findAll();
assertThat(carList).hasSize(databaseSizeBeforeDelete - 1);
}
}
В тесте используется H2 с этой конфигурацией:
spring:
application:
name: multithreaded_testing
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:h2:mem:multithreaded_testing;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
name:
username:
password:
hikari:
auto-commit: false
Неудачный тест: com.xti. web.rest.CarResourceIT # getAllCars
Impl: com.xti.service.impl.CarServiceImpl # findAll
https://bitbucket.org/Kelvijn/mockmvc_multithreaded_problem/src/master/