为什么尽管我没有更改任何日期值,entityManager.clear() 仍会因不同的日期值而导致我的测试失败?

问题描述 投票:0回答:1

因此,我正在运行 @DataJpaTest ,并在我的 setUp 函数中执行entityManager.clear(),最终将书籍对象与持久性上下文分离。但以下测试最终因错误而失败。

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)

但是当我注释掉entityManager.clear()行时,测试就通过了。 任何人都知道为什么会发生这种情况?我没有对任何书籍进行任何更改,那么为什么从数据库读取时日期会发生变化?

@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), firstSixBooks.get(j));
        }
    }

}

如有任何帮助或建议,我们将不胜感激!

即使使用entityManager.clear(),我也期望测试能够通过,但最终失败了,出于好奇,我想知道为什么。

java spring spring-boot spring-data-jpa entitymanager
1个回答
0
投票

即使使用entityManager.clear(),我也期望测试能够通过,但最终失败了,出于好奇,我想知道为什么。

当您使用

EntityManager
持久化实体对象时,该对象本身就会变得持久化。除其他外,这意味着该对象由
EntityManager
缓存。这也许是区分持久实体和分离实体的主要因素。

EntityManager
被请求提供已缓存的实体时,它会提供缓存的实例本身,而不是副本。当您不分离实体时,这就是您的测试中发生的情况。在这种情况下,您正在测试对象是否是
equals()
本身,这对于任何没有反常的、不合格的
Object
方法的
equals(Object)
来说都是如此。那么,
equals()
测试通过也就不足为奇了。

但是,如果您do分离实体,例如通过

clear()
ing
EntityManager
,那么当您请求它们时,它必须实例化新实体。在这种情况下,您可以比较具有相同属性值的不同对象。当且仅当您为实体类提供了产生该结果的
equals(Object)
方法时,它们才会比较相等。从
Object
继承的不会产生该结果。

特别是对于实体来说,是否应该为类配备这样的

equals()
方法是有争议的。但是,如果您决定这样做,那么您应该确保也实现兼容的
hashCode()
方法。

IMO,您的测试夹具应该清除

EntityManager
。如果您决定为
Book
类提供与您想要测试的条件相对应的
equals()
方法,那么这应该足以使您现有的测试通过。否则,您应该修改测试,以便它评估您想要检查的任何平等感。例如,这可能意味着比较一个或多个单独的字段。

© www.soinside.com 2019 - 2024. All rights reserved.