I want to test hibernate session\'s save() method using spring testing framework. @Test method is :
@Test
@Transactional
public void testSave() {
User ex
You should also take care of the importedpackage : in my case I imported
import javax.transaction.Transactional;
instead of
import org.springframework.transaction.annotation.Transactional;
@Transactional
tests (Spring Pitfalls: Transactional tests considered harmful). I've used @org.springframework.test.context.jdbc.Sql
to re-populate DB in my service tests and @Transactional
for controllers.ConstraintViolationException
for controller update test with invalid data have been thrown only when transaction is committed. So I've found 3 options:
@Commit
or with @Transactional(propagation = Propagation.NEVER)
. Be aware of DB change.TestTransaction
Code:
TestTransaction.flagForCommit();
TestTransaction.end();
TransactionTemplate
Code:
@Autowired
private PlatformTransactionManager platformTransactionManager;
@Test(expected = Exception.class)
public void testUpdate() throws Exception {
TransactionTemplate transactionTemplate = new TransactionTemplate(platformTransactionManager);
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
String json = ...
transactionTemplate.execute(ts -> {
try {
mockMvc.perform(put(REST_URL + USER_ID)
.contentType(MediaType.APPLICATION_JSON)
.content(json))
.andExpect(status().isOk());
...
} catch (Exception e) {
e.printStackTrace();
}
return null;
});
If flush
is not working then it very much depend on your database isolation level.
Isolation
is one of the ACID
properties of database, that defines how/when the changes made by one operation become visible to other concurrent operations.
I believe your isolation level is set to Read Committed
or Repeatable Read
.
Finally I stuck to the following solution:
First, my @Test
methods are not running within spring @Transactional
support. See this article to know how dangerous it may be. Next, instead of using @Repository
beans inside @Test
methods I autowire @Service
beans which use @Transactional
annotation.
The miracle is that @Test
method like this
@Test
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void testSave() {
Answer created = createAnswer();
Long generatedId = answerService.save(created);
//at this moment answer is already in db
Answer actual=getAnswerById(generatedId);
... }
puts my Answer object into database (just after answerService.save(created);
) and method getAnswerById
goes to DB and extracts it to check if save was correct.
To eliminate changes made to database in @Test
method I recreate database by JdbcTestUtils.executeSqlScript