user3417078
user3417078

Reputation: 265

How to tell Hibernate NOT to store data while running JUnit tests?

I want to check my persistence logic and so I am running some test cases.

Repository class:

@Repository
public class MyRepository {
    public void add(Object obj) {
        /* Do some stuff here */
        getSession().persist(obj);
    }
}

Test class:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { Context.class})
public class MyTests {
    @Inject
    private MyRepository myRepository;

    @Test
    @Rollback(true)
    public void foo() {
        /* Test logic */
        myRepository.add(obj);
        Assert.assert...;
    }
}

The unit test: MyTests.java contains test cases which test some stuff that is related to persistence, but not the actual Hibernate persistence itself, so that's why the getSession.persist() statement is obsolete.

For performance reasons, I want to prevent Hibernate from storing data to my database, even if the whole data interaction is rolled back. My approach would be to mock: getSession().persist(). Is there a better, or more specifically, an easier way to achieve my intentions?

Upvotes: 2

Views: 1351

Answers (3)

Iurii Volobuev
Iurii Volobuev

Reputation: 41

First of all, there are different id generators in Hibernate. If identity generator (not all the databases supports it), then to assign id to the entity, when session.persist method is called, insert query will be called. But if, for example, sequence or uuid generator is used, then insert won't be triggered (at least right away).

After that if methods session.get or session.load are called to load persisted (in the current session) object, then select query won't be called, because it gets object from Hibernate cache. But if HQL is used to select data, then select query is called. Moreover before it (by default) insert query for persisted object is called too.

This can be changed with FlushMode. By default is set to AUTO. It means:

The Session is sometimes flushed before query execution in order to ensure that queries never return stale state.

But if getSession().setHibernateFlushMode(FlushMode.MANUAL) is set:

The Session is only ever flushed when Session.flush() is explicitly called by the application.

Which means insert query won't be called until session.flush is called explicitly. If methods session.get and session.load are further used your code will still work (in the current session). But in case of select HQL query - it won't find the entity since it wasn't persisted. So beware.

Upvotes: 2

JamesENL
JamesENL

Reputation: 6540

You need to be able to mock your repository object so that you can use the mock in tests, and use the real one in the rest of your application.

DAO:

@Repository(value="MockRepo")
public class MockMyRepositoryImpl implments MyRepository {
    @Override
    public void add(Foo foo) {
        //Do nothing here
    }
}

Test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { Context.class})
public class MyTests {
    @Autowired
    @Qualifier("MockRepo");
    private MyRepository repo;

    @Test
    public void testFooSave() {
        repo.add(obj);
    }
}

The alternative is to use a mocking framework as detailed in another answer. Mocking frameworks are more flexible, but if you want something simple that's just going to work then try the above.

Upvotes: 0

mkierc
mkierc

Reputation: 1188

Create an interface, implement it using the Hibernate persist() method, and use it in such a way, that:

  • the normal calls go through the implementation
  • the test calls go through a mock version of it

public interface MyRepository {
    public void add(Object obj);
}

public class MyRepositoryImpl implements MyRepository {
    public void add(Object obj) {
        getSession().persist(obj);
    }
}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { Context.class})
public class MyTests {

    @Mock // we inject the mock instead of the true implementation
    private MyRepository myRepository;

    @Test
    @Rollback(true)
    public void foo() {
        /* Test logic */
        myRepository.add(obj); // the test uses the mocked version
        Assert.assert...;
    }
}

There are many Java libraries that let you mock objects, e.g.

Upvotes: 0

Related Questions