Rythmic
Rythmic

Reputation: 829

Reset JPA generated value between tests

I'm running spring + hibernate + JUnit with springJunit4runner and transactional set to default rollback I'm using in-memory derbydb as Database. Hibernate is used as a JPA Provider and I am successfully testing CRUD kinds of stuff. However, I have a problem with JPA and the behaviour of @GeneratedValue

If I run one of my tests in isolation, two entitys are persisted with id 1 and 2. If i run the whole test suite the ids are instead 6 and 7. Spring does rollbacks just fine so there are only these two entitys in the database after addition and of course zero before. But behaviour of @GeneratedValue doesn't allow me to reliable findById unless I would return the Id from the

dao.add(Entity e) //method

I don't feel like doing that for the sake of testing, or is it a good practise to return the entity that was persisted so I should be doing it anyway?

Upvotes: 6

Views: 15475

Answers (3)

GoldenSky
GoldenSky

Reputation: 67

in our project we use spring boot and h2 in memory db for test, and we solved it with the following annotation on the tests classes:

@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)

for example:

    @RunWith(SpringRunner.class)
    @AutoConfigureMockMvc
    @SpringBootTest(
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
        classes = Main.class
    )
    @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
    @TestPropertySource(locations = "classpath:application-test.properties")
    public class FooTest {

    }

Upvotes: 5

Thomas W
Thomas W

Reputation: 14164

Your tests shouldn't really be depending on particular ID values being generated.. ID assignment is the database & persistence layer's call, & not your responsibility to make assumptions about.

Doesn't dao.add(Entity e) set the ID/primary key property in the Entity? Normally Hibernate sets IDs before storing entities, for generated & sequence-allocated IDs at least.

(By the way, I strongly recommend using a portable (table-based) allocator and never depending on database-specific allocations mechanisms -- sequences or autoincrement columns. Portable allocators work faster & depending on proprietary key-allocation will make it very very much harder to ever run on a different database.)

In general, systems that save data do need a means of knowing what ID it has been saved to.. otherwise there would no reliable & unique means of retrieving it, which is the whole reason we have a PK in the first place!

So you might as well find out how to do it properly at this point.

Upvotes: 1

Rythmic
Rythmic

Reputation: 829

I found one way to do it. Manually alter table to restart/reset the auto_increment value. As I use Derby DB it is done by the following sql query issued as a native query call since I as stated use JPA API

em.createNativeQuery("ALTER TABLE konsult ALTER COLUMN id RESTART WITH 1").executeUpdate();

It's pretty self-explanatory but basically you provide the table name and the auto incrementing column of that table and then choose which value the first persisted row should be given.

Here is the way to do it with mysql: Resetting auto-increment value of MySql database with JPA

I'm still open to other suggestions though since this is sort of a hack and is in a way a dependency on other tests. It's also not RDBMS independent.

Upvotes: 0

Related Questions