0

I recently added the JpaTransactionManager to my Config and tried using Spring transactions. It seems to work correctly, except for one test which I have added below.

Why am I not getting my expected IllegalStateException? I expect this to fail, because CascadeType is set to NONE on the parentCategory field. If I add em.flush(); inside my repository class, I do get the expected exception.

As I understand it, adding @Transaction in my tests only adds the begin, commit and rollback transaction methods. So it should fail at the commit method, but it doesnt.

According to the Hibernate User Guide the hibernate.transaction.flush_before_completion is false by default. Is this the reason why I don't get my expected exception?

There is a similair post where a user states that the commit will cause a flush. This is also the reason why I decided to ask this question.


This is my entity

@Entity
@Table(name = "category")
public class Category {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "category_id", nullable = false, insertable = false, updatable = false)
  private Long id;

  @Column(name = "category", nullable = false, unique = true)
  private String categoryName;

  @ManyToOne // Default is CascadeType.NONE
  @JoinColumn(name = "parent_category_id", referencedColumnName = "category_id")
  private Category parentCategory;

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "parentCategory")
  private List<Category> childCategories = new ArrayList<>();

  public Category(String categoryName, Category parentCategory) {
    this.categoryName = categoryName;
    this.parentCategory = parentCategory;
  }

  // default constructor, getters and setters ...
}

This is my repository

@Repository
public class CategoryDaoImpl {

  @PersistenceContext protected EntityManager em;

  @Override
  public E persist(E entity) {
    em.persist(entity);
    // em.flush(); // Why doesnt Spring transactions automatically add the em.flush()  inside the transaction?
    return entity;
  }

}

This is my test

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DbConfig.class)
@Transactional
public class CategoryDaoTest {

  @Autowired private CategoryDao categoryDao;

  @Test(expected = IllegalStateException.class)
  public void createTwoCategoriesPersistChildAndGetIllegalStateException() {
    Category childCategory = new Category("firstChild", new Category("rootCategory", null));

    categoryDao.persist(childCategory);
  }

}

This is my config

@Configuration
@ComponentScan(basePackages = "nl.yoshuan.pricecomparer")
@EnableTransactionManagement
public class TestConfig {

  @Bean
  public DataSource dataSource() {
    EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
    return builder.setType(EmbeddedDatabaseType.HSQL).build();
  }

  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setPackagesToScan("nl.yoshuan.pricecomparer.entities");
    factory.setDataSource(dataSource());

    Map<String, Object> jpaProperties = new HashMap<>();
    jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
    jpaProperties.put("hibernate.show_sql", true);
    jpaProperties.put("hibernate.format_sql", true);
    jpaProperties.put("hibernate.use_sql_comments", true);
    jpaProperties.put("hibernate.hbm2ddl.auto", "create-drop");
    factory.setJpaPropertyMap(jpaProperties);

    return factory;
  }

  @Bean
  public PlatformTransactionManager transactionManager() {
    JpaTransactionManager txManager = new JpaTransactionManager();
  txManager.setEntityManagerFactory(entityManagerFactory().getObject());
    return txManager;
  }

}

This is my console output

2017-05-29 15:43:14 INFO  TransactionContext:101 - Began transaction (1) for test context [DefaultTestContext@971e903 testClass = CategoryDaoUTest, testInstance = nl.yoshuan.pricecomparer.dao.CategoryDaoUTest@2b2f5fcf, testMethod = addTwoCategoriesPersistChildAndGetIllegalStateException@CategoryDaoUTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@108531c2 testClass = CategoryDaoUTest, locations = '{}', classes = '{class nl.yoshuan.pricecomparer.config.TestConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@7661b5a]; rollback [true]
Hibernate: 
    /* insert nl.yoshuan.pricecomparer.entities.Category
        */ insert 
        into
            category
            (category_id, category, parent_category_id) 
        values
            (default, ?, ?)
2017-05-29 15:43:14 INFO  TransactionContext:136 - Rolled back transaction for test context [DefaultTestContext@971e903 testClass = CategoryDaoUTest, testInstance = nl.yoshuan.pricecomparer.dao.CategoryDaoUTest@2b2f5fcf, testMethod = addTwoCategoriesPersistChildAndGetIllegalStateException@CategoryDaoUTest, testException = java.lang.AssertionError: Expected exception: java.lang.IllegalStateException, mergedContextConfiguration = [MergedContextConfiguration@108531c2 testClass = CategoryDaoUTest, locations = '{}', classes = '{class nl.yoshuan.pricecomparer.config.TestConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]].
2017-05-29 15:43:14 INFO  GenericApplicationContext:987 - Closing org.springframework.context.support.GenericApplicationContext@49206065: startup date [Mon May 29 15:43:14 CEST 2017]; root of context hierarchy
2017-05-29 15:43:14 INFO  LocalContainerEntityManagerFactoryBean:548 - Closing JPA EntityManagerFactory for persistence unit 'default'
2017-05-29 15:43:14 INFO  SchemaDropperImpl$DelayedDropActionImpl:524 - HHH000477: Starting delayed drop of schema as part of SessionFactory shut-down'
Hibernate: 

    alter table category 
       drop constraint FKs2ride9gvilxy2tcuv7witnxc
Hibernate: 

    drop table category if exists
2017-05-29 15:43:14 INFO  EmbeddedDatabaseFactory:217 - Shutting down embedded database: url='jdbc:hsqldb:mem:testdb'

java.lang.AssertionError: Expected exception: java.lang.IllegalStateException

    at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:32)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Yoshua Nahar
  • 1,304
  • 11
  • 28

1 Answers1

0

I think you should add @TransactionConfiguration to your unit test. TransactionConfiguration defines class-level metadata for configuring transactional tests.

Luay Abdulraheem
  • 751
  • 3
  • 11
  • `@TransactionConfiguration` is deprecated and is not what I'm looking for. Neither is `@Rollback`. `@Commit` does work, but the exception is now occuring after my method. I get `java.lang.AssertionError: Expected exception: java.lang.IllegalStateException` and after that, I get my InvalidDataAccessApiUsageException --> TransientPropertyValueException --> IllegalStateException stacktrace – Yoshua Nahar May 30 '17 at 12:09