Dave
Dave

Reputation: 19260

How do I test my DAO update method in an AbstractTransactionalJUnit4SpringContextTests test?

I'm using Java 8, JUnit 4.12, Spring 4, and Hibernate 5.2.12.Final. I want to test a Hibernate method where I update some rows. The method looks like this

        final CriteriaBuilder qb = m_entityManager.getCriteriaBuilder();
        final CriteriaUpdate<FailedEvent> q = qb.createCriteriaUpdate(FailedEvent.class);
        final Root<FailedEvent> root = q.from(FailedEvent.class);
        q.where(qb.and( qb.equal(root.get(FailedEvent_.objectId), objectId) ));
        q.set(root.get(FailedEvent_.flaggedForDelete), true);
        affectedRows = m_entityManager.createQuery(q).executeUpdate();
     return affectedRows > 0;

I have the following JUnit test to verify this

public class FailedEventDaoTest extends AbstractTransactionalJUnit4SpringContextTests
...

    @Test
    public final void testFlagForDeleteByObjectId()
    {
            final String eventId = "testId";
            final FailedEvent event = failedEventDao.findByEventId(eventId);
            Assert.assertFalse("A pre-condition fo this test is that an failed_event record with id \"" + eventId + "\" have a non-empty object id.", StringUtils.isEmpty(event.getObjectId()));
            Assert.assertTrue(failedEventDao.flagForDeleteByObjectId(event.getObjectId()));
            final FailedEvent foundEvent = failedEventDao.findByEventId(eventId);
            Assert.assertTrue("Failed to mark flag for deletion.", foundEvent.getFlaggedForDelete());
    }   // testFlagForDeleteByObjectId

But my test fails on the last line,

Assert.assertTrue("Failed to mark flag for deletion.", foundEvent.getFlaggedForDelete());

Is this because the transaction hasn't completed yet so nothing has been updated in the database? What's the way I can validate that the right records are updated?

Upvotes: 9

Views: 1822

Answers (2)

DCO
DCO

Reputation: 1292

You should consider not to extend the abstract class and use a different approach. For example

@RunWith(SpringJUnit4ClassRunner.class) 
@Transactional

on the class.

Like:

  package com.example;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import com.example.model.Person;
import com.example.service.PersonService;

@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@ContextConfiguration("classpath:/spring-beans.xml")
public class PersonServiceIntegrationTests {
    @Autowired
    private PersonService personService;

    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Test
    public void shouldCreateNewPerson() {
        Person person = new Person();
        person.setFirstName("Kenan");
        person.setLastName("Sevindik");

        long countBeforeInsert = jdbcTemplate.queryForObject("select count(*) from t_person", Long.class);
        Assert.assertEquals(2, countBeforeInsert);

        personService.create(person);

        long countAfterInsert = jdbcTemplate.queryForObject("select count(*) from t_person", Long.class);
        Assert.assertEquals(3, countAfterInsert);
    }

    @Test
    public void shouldDeleteNewPerson() {
        long countBeforeDelete = jdbcTemplate.queryForObject("select count(*) from t_person", Long.class);
        Assert.assertEquals(2, countBeforeDelete);

        personService.delete(1L);

        long countAfterDelete = jdbcTemplate.queryForObject("select count(*) from t_person", Long.class);
        Assert.assertEquals(1, countAfterDelete);
    }

    @Test
    public void shouldFindPersonsById() {
        Person person = personService.findById(1L);

        Assert.assertNotNull(person);
        Assert.assertEquals("John", person.getFirstName());
        Assert.assertEquals("Doe", person.getLastName());
    }
}

Check this out https://examples.javacodegeeks.com/enterprise-java/spring/write-transactional-unit-tests-spring/#section_7

Or

  @RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(

  classes = { StudentJpaConfig.class }, 

  loader = AnnotationConfigContextLoader.class)

@Transactional

public class InMemoryDBTest {

     

    @Resource

    private StudentRepository studentRepository;

     

    @Test

    public void givenStudent_whenSave_thenGetOk() {

        Student student = new Student(1, "john");

        studentRepository.save(student);

         

        Student student2 = studentRepository.findOne(1);

        assertEquals("john", student2.getName());

    }

}

Check this out https://www.baeldung.com/spring-jpa-test-in-memory-database

Upvotes: 3

DCO
DCO

Reputation: 1292

Try @AfterTransaction Annotation to test the result.

    @AfterTransaction
    public final void theRealTest()
    {
            Assert.assertTrue("Failed to mark flag for deletion.", foundEvent.getFlaggedForDelete());
    }

https://www.springbyexample.org/examples/simple-spring-transactional-junit4-test-code-example.html

if this is also not working try:

"So, you need to create multiple transactions inside your test method. As you can see, you cannot use AbstractTransactionalJUnit4SpringContextTests, because it creates a single transaction for the whole test method, and cannot use bare AbstractJUnit4SpringContextTests, because it creates no transactions at all.

The solution is to use AbstractJUnit4SpringContextTests and manage transactions inside your test method programmatically.

You need to inject PlatformTransactionManager into your test, create TransactionTemplate from it and use it to demarcate your transactions as described in 11.6 Programmatic transaction management."

found here: Using AbstractTransactionalJUnit4SpringContextTests with commit halfway through

Upvotes: 4

Related Questions