Reputation: 478
The test method remove
is trying to remove some user with the id 147
but this id does not exist. If I enable Rollback(false)
I get an exception (the expected behavior) but without it, the test pass without problems. So I have two questions:
UserDao
is inheriting from a generic DAO class which has the @Transactional
(default options) and @Repository
(with the bean name) annotations at class level.
Here is the exception I get when disabling rollback.
I am using Spring Framework 4.3.9, Hibernate 5.2.10 and JUnit 4.12
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@Transactional
@ContextConfiguration({
"classpath:myapp-config-test.xml",
"classpath:hib-test.xml"})
public class UserControllerTest {
private MockMvc mockMvc;
private MvcResult mvcResult;
private final String basePath = "/users/";
@Autowired
private UserDao userDao;
@Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(new UserController(userDao)).build();
}
@Test
//@Rollback(false)
public void remove() throws Exception {
mockMvc.perform(delete(basePath + "147")).andExpect(status().isOk());
}
}
Upvotes: 0
Views: 590
Reputation: 691625
Read the stack trace, from bottom to top:
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:67)
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:54)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:46)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3315)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3552)
at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:99)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:589)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1435)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:491)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3201)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2411)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:467)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:146)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:220)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:68)
at org.springframework.orm.hibernate5.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:582)
... 24 more
You can see that the exception happens when the transaction manager commits the transaction:
at org.springframework.orm.hibernate5.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:582)
Committing the transaction causes the Hibernate session to flush the changes that have been made, and kept in memory:
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3201)
And indeed, the flush causes the deletion to actually be executed on the database:
at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:99)
And since the deletion doesn't delete anything, the exception is thrown:
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
So, in order to actually execute the deletion, and to throw the expected exception, you need to flush.
But you shouldn't test the behavior of a DAO (and even less, the behavior of Hibernate, which is already tested by Hibernate itself), in the unit test of an MVC controller. Instead, you should mock the dependencies of the controller (i.e. the DAO) when unit-testing the controller. And have another test for the DAO.
Upvotes: 2