Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using bidirectional associations from domain objects in @Transactional Junit Tests

I have a @Transactional JUnit Test set up and I want to persist some test data to the database and also test if the associations are correct. However, when testing the associations, they always evaluate to null, even though it does work in a non-transactional test.

I persist two objects using the @Before annotation:

@Before
public void testData() {
    TestObjectOne o = new TestObjectOne();
    o.setName("One");
    repo.saveEntity(o); //autowired

    TestObjectTwo t = new TestObjectTwo();
    t.setOne(o);
    t.setName("Two");
    repo.saveEntity(t);
}

When accessing those two objects in a test, I get the correct instances:

    TestObjectOne o = repo.getOneByName("One");
    TestObjectOne t = repo.getTwoByName("Two");

When checking on the association between t and o, I get a correct reference because I explicitly defined that association:

    Assert.assertNotNull(t.getOne());

But when checking on the other way round, the object o is not correctly updated:

    Assert.assertNotNull(o.getTwos());

The association is defined in the domain object as

In One:

   @OneToMany(mappedBy = "one", fetch = FetchType.EAGER)
   private List<Two> twos;

In Two:

  @ManyToOne(optional = false)
  private One one;

When I have the test not run as @Transactional, it works nicely however.

edit saving the entities inside the test instead of the @Before method, doesn't make any difference.

like image 380
chzbrgla Avatar asked Oct 10 '22 13:10

chzbrgla


1 Answers

You need to flush and clear the current session after saving and before loading test objects for assertions.

When You save the TestObjectOne o the instance of it is kept in Hibernate session. Than You create TestObjectTwo t and add reference to o and save it so this instance is now also kept in Hibernate session. Than when You call get Hibernate gets You the instances You created earlier without updating them to reflect the actual state. So You need to flush and clear the session before loading - than the session L1 cache will be empty, and entities will be loaded corectly.

public class MyTest {

    @Before
    public void setUp() {

        TestObjectOne o = new TestObjectOne();
        o.setName("One");
        repo.saveEntity(o); //autowired

        TestObjectTwo t = new TestObjectTwo();
        t.setOne(o);
        t.setName("Two");
        repo.saveEntity(t);

        /* push all changes to current transaction*/
        repo.getSessionFactory().getCurrentSession().flush();
        /* clean current session, so when loading objects they'll
           be created from sratch and will contain above changes */
        repo.getSessionFactory().getCurrentSession().clear();
    }

    @Test
    public void test() {
        TestObjectOne o = repo.getOneByName("One");
        TestObjectOne t = repo.getTwoByName("Two");

        Assert.assertNotNull(t.getOne());
        Assert.assertNotNull(o.getTwos());
    }
}
like image 168
Roadrunner Avatar answered Oct 20 '22 06:10

Roadrunner