dadrus / jpa-unit

JUnit extension to test javax.persistence entities
Apache License 2.0
29 stars 9 forks source link

Database not cleaned up after test #47

Open holyhoehle opened 5 years ago

holyhoehle commented 5 years ago

When I run the following code I would expect that the database is always cleared after each test and so the results of test1() and test2() would be the same. However test2() returns two elements instead of the expected 1.

@ExtendWith(JpaUnit.class)
class CleanupTest {

    @PersistenceContext(unitName = "my-test-unit")
    private EntityManager entityManager;

    @BeforeEach
    void setup() {
        Test t1 = new Test();
        t1.setName("Test1");
        entityManager.persist(t1);
    }

    @Test
    void test1() {
        List list = entityManager.createQuery("select t from Test t").getResultList();
        System.out.println(list.size()); // 1
    }

    @Test
    void test2() {
        List list = entityManager.createQuery("select t from Test t").getResultList();
        System.out.println(list.size()); // 2
    }
}

Is there anything that I'm missing here? I tried with several combinations of the @Cleanup and @Transactional annotations at class and method level, but the result was always the same.

dadrus commented 5 years ago

I'll try to take a closer look at it in the next few days. It looks like the @Before* methods are not properly handled.

dadrus commented 5 years ago

which JPA provider and which DB are you using? I just did a copy&paste of your code above and with JPA 2.1 hibernate implementation with h2 I receive a "1" each time.

dadrus commented 5 years ago

One additional thing: The transaction "closure" encloses the entire test, including the setup (@BeforeEach in JUnit5 and @Before in JUnit4) and tear down steps (@AfterEach in JUnit5 and @After in JUnit4). That means, the query result you see in a test setup, like yours, comes from the JPA cache and not from the DB itself. Same is true for @Cleanup and other "closures" defined by jpa-unit in a sense that they all enclose all setup steps, the actual test method and the tear down steps. At least for regular JUnit tests.

I see a benefit of having a more fine grained control, which is not given yet. #33 addresses such functionality. To enable that means however a pretty huge refactoring of the existing code base, so I don't know, when it will be available.

holyhoehle commented 5 years ago

OK, thanks for the explanation. I will then try to use the @InitialDatasets annotation when I need to populate the database.

I'm stuck with an ancient Hibernate 4.2.11 and and JPA 2.0 but I'm planning to update soon™ to up-to-date versions. The DB I'm using is HSQLDB.

dadrus commented 5 years ago

You can also use the TransactionSupport class and do something like

Test t1 = new Test();
t1.setName("Test1");
newTransaction(manager).execute(() -> {
  entityManager.persist(t1);
});

in your setup method. It will suspend the transaction started by default and open and commit a new one for the lambda block. It may be worth to clean the entityManager on commit, so the chained method clearContextOnCommit(true) can be handy.

Please try it say if it helps.

If I can find some time, I'll check the functionality with you "ancient" setup :)

holyhoehle commented 5 years ago

Unfortunately, your suggestion didn't work either. I get the same result as before. clearContextOnCommit(true) also doesn't make a difference.

dadrus commented 5 years ago

is it possible for you to send me your test project for better analysis?

holyhoehle commented 5 years ago

Sorry for the long delay, but here's a test project that reproduces the issue.

jpaunittest.zip