views:

70

answers:

2

Hello,

In my testing code I need to have a blank/empty database at each method. Is there code that would achieve that, to call in the @Before of the test?

A: 

Actually you always can use JPQL,

em
   .createQuery("DELETE FROM MyEntity m")
   .executeUpdate()
;

But note, there is no grants that entity cache would be cleaned also. But for unit-test purposes it is look like good solution.

Dewfy
and how do you write that with the criteria api? I see no delete(). Is it only for DML?
simpatico
Yes, this delete is DML.My usual scenario of test is to add @BeforeClass and @AfterClass (for your case change it to @Before and @After). In "after" the cleaning code deallocates all added records: em.createQuery("DELETE FROM MailMessage m where m.mailMessageId = :id").setParameter("id", message.getMailMessageId()).executeUpdate();So may be this is answer how to provide criteria
Dewfy
em.clear() before seems to solve the cache issue.
simpatico
and how do I delete when I have a dependency/foreign key on both sides (cycle) of the entities I want to delete?Something, like defer checking.
simpatico
@simpatico: The bulk DELETE doesn't cascade (per specification).
Pascal Thivent
@simpatico - either you need to add CASCADE constraint on DDL, or manually drop all dependency by stand-alone invoke DELETE for each entity
Dewfy
I've added (cascade=CascadeType.ALL) to every @ relation in every entity (isn't that what I should do?), but I still get an exception trying to delete.
simpatico
As I wrote, bulk delete operations are **NOT** cascaded per specification (section 4.10).
Pascal Thivent
emf.getCache().evictAll(); clears the cache.
simpatico
A: 

In my testing code I need to have a blank/empty database at each method.

I would run the test methods insider a transaction (and rollback at the end of each method). That's the usual approach. I don't see the point of committing a transaction and writing data to the database if you DELETE them just after. Just don't commit.

An alternative (not exclusive) would be to use DbUnit to put your database in a known state before a test execution. When doing this, you usually don't need to clean it up.

Another option would be to use raw JDBC to drop the database if exists and then have JPA recreate the whole database. Will be pretty slow though.

Pascal Thivent
I see the point. I test a whole 'action' that also writes to the database, and then I compare the database state against expectations. The transaction is committed behind the methods I test (I test from much outside).
simpatico
@simpatico: And don't you think that this kind of details could help to get good answers?
Pascal Thivent
I'll look into dbUnit, I think I'm also having cache issues, since running each test separately works, but together not (it claims the presence of residual data from another test).Would it be recommended to have a singleton entity manager in the whole app? The tutorials I've seen don't do that.
simpatico
@simpatico: *Would it be recommended to have a singleton entity manager in the whole app?* I don't think so. The most common pattern in a multi-user client/server application is *entitymanager-per-request*.
Pascal Thivent
I'm in a single-user desktop app. I've one em (actually a wrapper class) shared by all tests. Would you recommend each test having it's own em?I'm surprised that clearing the cache after each test still results in my problem. I'm sure it's not a persisted problem because the delete code is executed successfully.
simpatico