So I am running a @DataJpaTest and in my setUp function, I do entityManager.clear() which ends up detaching the books objects from the persistence context. But the following test ends up failing with the error.
Error when comparing the whole Book entity ->
BookRepositoryTest > doSomething() FAILED
org.opentest4j.AssertionFailedError: expected: <Book(id=6, title=Pride and Prejudice, price=16.99, quantity=12, author=Jane Austen, ISBN=890-1234567890, genre=Romance, publishDate=1813-01-28)> but was: <Book(id=6, title=Pride and Prejudice, price=16.99, quantity=12, author=Jane Austen, ISBN=890-1234567890, genre=Romance, publishDate=1813-01-27)>
at app//org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
at app//org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
at app//org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
at app//org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
at app//org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177)
at app//org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1145)
at app//library.backend.api.BookRepositoryTest.doSomething(BookRepositoryTest.java:55)
Error when only comparing the dates ->
BookRepositoryTest > doSomething() FAILED
org.opentest4j.AssertionFailedError: The dates do not match ==> expected: <1813-01-28> but was: <1813-01-27>
at app//org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
at app//org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
at app//org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
at app//org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
at app//org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1156)
at app//library.backend.api.BookRepositoryTest.doSomething(BookRepositoryTest.java:55)
But the moment I comment out the entityManager.clear() line, the tests pass. Anyone has any idea why this happens? I am not making any changes to any of the books so why are the dates being changed when reading from the db?
@ExtendWith(SpringExtension.class)
@DataJpaTest
@ActiveProfiles(profiles = {"test"})
public class BookRepositoryTest {
@Autowired
private BookRepository bookRepository;
@Autowired
private TestEntityManager entityManager;
private ObjectMapper mapper;
@Value("classpath:books.json")
Resource booksJson;
List<Book> books;
@BeforeEach
void setUp() throws Exception{
mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
books = mapper.readValue(booksJson.getInputStream(),
new TypeReference<List<Book>>(){});
books.forEach(entityManager::persistAndFlush);
entityManager.clear();
}
@Test
void doSomething(){
List<Book> firstSixBooks = bookRepository.findAll(PageRequest.of(0,6)).toList();
assertEquals(6, firstSixBooks.size());
for(int j=0; j<6; j++){
assertEquals(books.get(j).getPublishDate(), firstSixBooks.get(j).getPublishDate());
}
}
}
Any help or advices are appreciated!
I am expecting for the tests to pass even with entityManager.clear() and it is ends up failing, I want to know why out of curiosity.
When you persist an entity object using an
EntityManager, that object itself becomes persistent. Among other things, it means that that object is cached by theEntityManager. That's perhaps the main thing that distingishes a persistent entity from a detached one.When an
EntityManageris asked for an entity that it already has cached, it provides the cached instance itself, not a copy. This is what happens in your test when you do not detach the entities. In this case, you are testing whether objects areequals()themselves, which is true of anyObjectthat does not have a perverse, non-conformingequals(Object)method. It is in no way surprising, then, that theequals()tests pass.But if you do detach the entities, by
clear()ing theEntityManager, for example, then it must instantiate new ones when you request them. In this case, you compare distinct objects with equal property values. These will compare equal if and only if you have given the entity class anequals(Object)method that produces that result. The one inherited fromObjectwill not produce that result.Especially for entities, it's debatable whether you should equip classes with such an
equals()method. If you decide to do, however, then you should make sure to implement a compatiblehashCode()method as well.IMO, your test fixture should clear the
EntityManager. If you decide to give theBookclass anequals()method corresponding to the conditions you want to test then that should be sufficient to make your existing test pass. Otherwise, you should modify the test so that it evaluates whatever sense of equality you want to check. For example, that might mean comparing one or more individual fields.