Home > other >  @Version field in entity class not increased during JPA test even though I updated it
@Version field in entity class not increased during JPA test even though I updated it

Time:07-18

I have a simple Repository:

public interface ReviewRepository extends CrudRepository<ReviewEntity, Integer> {

  @Transactional(readOnly = true)
  List<ReviewEntity> findByProductId(int productId);
}

I want to test it using test containers I followed the procedures and wrote my test case:

public abstract class MySqlTestBase {
  private static MySQLContainer database = new MySQLContainer("mysql:5.7.32");

  static {
    database.start();
  }

  @DynamicPropertySource
  static void databaseProperties(DynamicPropertyRegistry registry) {
    registry.add("spring.datasource.url", database::getJdbcUrl);
    registry.add("spring.datasource.username", database::getUsername);
    registry.add("spring.datasource.password", database::getPassword);
  }

}



@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class PersistTests extends MySqlTestBase {

  @Autowired
  private ReviewRepository repository;

  private ReviewEntity savedEntity;

  @BeforeEach
  void setupDb() {
    repository.deleteAll();

    ReviewEntity entity = new ReviewEntity(1, 2, "author1");
    savedEntity = repository.save(entity);
    assertEqualsReview(entity, savedEntity);
  }

  @Test
  void update() {
    savedEntity.setAuthor("author2");
    repository.save(savedEntity);



       ReviewEntity foundEntity = repository.findById(savedEntity.getId()).get();
       assertEquals(1, (long)foundEntity.getVersion());
       assertEquals("author2", foundEntity.getAuthor());
          }
    }

my ReviewEntity also is written like:

@Entity
public class ReviewEntity {

  @Id @GeneratedValue
  private int id;

  @Version
  private int version;

  private int productId;
  private int reviewId;
  private String author;

  public ReviewEntity(int productId, int reviewId, String author) {
        this.productId = productId;
        this.reviewId = reviewId;
        this.author = author;
}

          // setter and getter
    
    }

When I run this test it fails at the assertEquals(1, (long)foundEntity.getVersion()); line with this message:

expected: <1> but was: <0>
Expected :1
Actual   :0

But I update the ReviewEntity class and according to the documentation the @Version field should automatically increases but this not happens. what part of my test is wrong?

CodePudding user response:

If you look at the default implementation of save method in CrudRepository interface in the SimpleJpaRepository class you will see save method is implemented like:

@Transactional
@Override
public <S extends T> List<S> saveAll(Iterable<S> entities) {

    Assert.notNull(entities, "Entities must not be null!");

    List<S> result = new ArrayList<S>();

    for (S entity : entities) {
        result.add(save(entity));
    }

    return result;
}

meaning it is marked with @Transactional with Required as its propagation level(it is default)

Required propagation works like this:

REQUIRED is the default propagation. Spring checks if there is an active transaction, and if nothing exists, it creates a new one. Otherwise, the business logic appends to the currently active transaction

and for DataJpaTest annotation comment section says:

By default, tests annotated with @DataJpaTest are transactional and roll back at the end of each test

So for method update in your test a transaction is going to be created and the save method in repository.save(savedEntity); is going to be appended to that transaction. meaning it is committed only if that transaction successfully committed and we now know that's not going to happen.

A workaround for this problem probably would be to annotate test class with @Transactional(propagation = NOT_SUPPORTED) to suspends the currently running transaction then for repository.save(savedEntity); a transaction is going to be created and committed at the end of save method and then you can proceed in your test.

  • Related