Контекст:< /strong>
- Я не использую MockMvc, а напрямую тестирую с помощью BeerRepository и
beerController. - База данных H2 загружает 3 объекта Beer при запуске.
- Тестовый класс помечен @SpringBootTest, а конкретный
тест использует @Transactional и @Rollback для обеспечения изменения состояния базы данныхобратно после выполнения.
Последовательность выполнения теста:
- Получите первое пиво через BeerRepository, чтобы получить действительный UUID.
- Сопоставьте объект Beer с объектом BeerDTO с помощью преобразователя.
- Установите для свойства BeerName BeerDTO новое значение.
- Вызовите updateById на BeerController с UUID и измененным BeerDTO.
- Утвердите несколько условий, включая это версия увеличивается на
1.
Тест не выполняется при утверждении версии. Ожидаемое значение — 1, а фактическое — 0.
Наблюдения:
[*] Тест пройдет успешно, если я удалю @Rollback и @Transactional.
[*]Тест также пройдет, если я использую saveAndFlush вместо сохранения в
BeerServiceJPA.
< /ul>
Может ли кто-нибудь объяснить, почему это происходит и как это исправить? Я считаю, что @Transactional и @Rollback здесь имеют смысл, поскольку в идеале обновление следует откатить после теста.
Вот соответствующий код (упрощенный для краткости):
сущности/Пиво
@Getter
@Setter
@ToString
@Builder
@Entity
@NoArgsConstructor
@AllArgsConstructor
public class Beer {
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
@Column(length = 36, columnDefinition = "varchar", updatable = false, nullable = false)
private UUID id;
@Version
private Integer version;
private String beerName;
private BeerStyle beerStyle;
private String upc;
private Integer quantityOnHand;
private BigDecimal price;
private LocalDateTime createdDate;
private LocalDateTime updateDate;
}
репозитории/Репозиторий пива
public interface BeerRepository extends JpaRepository {
}
услуги/BeerService
public interface BeerService {
void updateBeerById(UUID beerId, BeerDTO beer);
}
services/BeerServiceJPA
@Service
@Primary
@RequiredArgsConstructor
public class BeerServiceJPA implements BeerService {
private final BeerRepository beerRepository;
private final BeerMapper beerMapper;
@Override
public void updateBeerById(UUID beerId, BeerDTO beer) {
beerRepository.findById(beerId).ifPresent(foundBeer -> {
foundBeer.setBeerName(beer.getBeerName());
foundBeer.setBeerStyle(beer.getBeerStyle());
foundBeer.setUpc(beer.getUpc());
foundBeer.setPrice(beer.getPrice());
beerRepository.save(foundBeer);
});
}
}
контроллеры/BeerController
@Slf4j
@RequiredArgsConstructor
@RestController
public class BeerController {
public static final String BEER_PATH = "/api/v1/beer";
public static final String BEER_PATH_ID = BEER_PATH + "/{beerId}";
private final BeerService beerService;
@PutMapping(BEER_PATH_ID)
public ResponseEntity updateById(@PathVariable("beerId")UUID beerId, @RequestBody BeerDTO beer){
beerService.updateBeerById(beerId, beer);
return new ResponseEntity(HttpStatus.NO_CONTENT);
}
тесты/контроллеры/BeerControllerIT
@SpringBootTest
class BeerControllerIT {
@Autowired
BeerController beerController;
@Autowired
BeerRepository beerRepository;
@Autowired
BeerMapper beerMapper;
@Rollback
@Transactional
@Test
void updateExistingBeer() {
Beer beer = beerRepository.findAll().get(0);
Integer version = beer.getVersion();
BeerDTO beerDTO = beerMapper.beerToBeerDto(beer);
beerDTO.setId(null);
beerDTO.setVersion(null);
final String beerName = "UPDATED";
beerDTO.setBeerName(beerName);
ResponseEntity responseEntity = beerController.updateById(beer.getId(), beerDTO);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatusCode.valueOf(204));
Beer updatedBeer = beerRepository.findById(beer.getId()).get();
System.out.println(updatedBeer);
assertThat(updatedBeer.getBeerName()).isEqualTo(beerName);
assertThat(updatedBeer.getVersion()).isEqualTo(version+1);
}
}
Подробнее здесь: https://stackoverflow.com/questions/791 ... ctional-an