4

I have a very simple spring test using @DataJpaTest and @Transactional:

@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
@Transactional
@Rollback
@ComponentScan(basePackages = "com.acma")
public class FooTest {
  @Autowired
  private EntityManager em;

  @Test
  public void persist() throws Exception {
    em.persist(new Foo());
  }
}

@Entity
public class Foo {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
}

According to the documentation, each test case should run in its own transaction and be rolled back at the end of each test case, but this is not happening.

What's even stranger is that in the logs I see:

2018-05-02 19:47:07.246  INFO 97919 --- [           main] o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context [DefaultTestContext@317890ea testClass = FooTest, testInstance = com.acma.FooTest@2c719bd4, testMethod = persist@FooTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@53aa38be testClass = FooTest, locations = '{}', classes = '{class com.acma.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@37a0ec3c key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@5be6e01c, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@7ce3cb8e, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@70e8f8e, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@e831c7a, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@636be97c], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@6f9e08d4]; rollback [true]
Hibernate: insert into foo values ( )
2018-05-02 19:47:07.575  INFO 97919 --- [           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test context [DefaultTestContext@317890ea testClass = FooTest, testInstance = com.acma.FooTest@2c719bd4, testMethod = persist@FooTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@53aa38be testClass = FooTest, locations = '{}', classes = '{class com.acma.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@37a0ec3c key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@5be6e01c, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@7ce3cb8e, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@70e8f8e, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@e831c7a, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@636be97c], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]].
Chico Sokol
  • 1,254
  • 3
  • 16
  • 24

1 Answers1

1

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

so you don't need the extra @Transactional & @Rollback

here an example have a look at @AfterTransaction and its output.

In your example, you could try to retrieve your saved entity in this method, you won't find it.

 @RunWith(SpringRunner.class)
 @DataJpaTest
 public class TransactionTest {

   @Autowired PersonRepository repo;

   @Before
   public void showCountBefore() {
     System.err.println("before: " + repo.count());
   }

   @After
   public void showCountAfter() {
    System.err.println("after: " + repo.count());
   }

   @AfterTransaction
   public void showCountAfterTransaction() {
     System.err.println("after tx: " + repo.count());
   }

   @Test
   public void testRollback() {
     repo.save(new Person("Deyne", "Dirk", "dirkdeyne"));
     System.err.println("saved: " + repo.count());
   }

}

this will print out

  • before: 5
  • saved: 6
  • after: 6
  • after tx: 5
Dirk Deyne
  • 6,048
  • 1
  • 15
  • 32
  • I changed my example removing the annotations you mentioned but it didn't help, this is the modified version: https://gist.github.com/csokol/a37356da3400d57edc1e460e9674efdc Maybe the reason why that's not working is that I'm not using an in memory db? Also I'm using spring boot 2.x... – Chico Sokol May 03 '18 at 09:31
  • yep, when I change it to use an in memory db (removing the `@AutoConfigureTestDatabase(replace = Replace.NONE)`) the transaction rollback works. – Chico Sokol May 03 '18 at 09:38
  • that is strange! `@AutoConfigureTestDatabase(replace = Replace.NONE)` don't makes any difference in my example. I did try with EntityManager persist, it also works... Maybe you have to flush `em.flush();` after the persist? – Dirk Deyne May 03 '18 at 10:01
  • Which spring boot version are you using? – Chico Sokol May 03 '18 at 12:15
  • @DirkDeyne I got it working using this https://stackoverflow.com/a/49997835/4188368 – Richa Dec 21 '18 at 06:44