【问题标题】:Why FetchType.EAGER doesn't work in unit tests?为什么 FetchType.EAGER 在单元测试中不起作用?
【发布时间】:2019-02-18 05:39:50
【问题描述】:

我的 JPA (Hibernate) 和 Spring 应用程序。我的实体是:

部门

@Entity
@Table(schema = "myschema")
public class Department {

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    @Column(columnDefinition = "BINARY(16)", length = 16 )
    private UUID uuid;

    @Column(name = "name", length = 200, nullable = false)
    private String name;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "department", cascade = CascadeType.ALL, orphanRemoval = true)
    List<User> users = new ArrayList<>();
}

用户

@Entity
@Table(schema = "myschema")
public class User {

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    @Column(columnDefinition = "BINARY(16)", length = 16 )
    private UUID uuid;

    @NotNull
    @Column(name = "login", length = 100, nullable = false)
    private String login;

    @ManyToOne
    @JoinColumn(name = "department_fk", nullable = false)
    private Department department;

}

DAO 用于部门:

@Repository("departmentDao")
public class DepartmentDao {

    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    public UUID save(Department entity) {
        log.info("Department entity will be persisted", entity);
        entityManager.persist(entity);
        return entity.getUuid();
    }

    @Transactional
    public List<Department> getAllWithUsers() {
        log.info("Select all departments");
        CriteriaQuery<Department> criteria = entityManager.getCriteriaBuilder().createQuery(Department.class);
        Root<Department> root = criteria.from(Department.class);
        criteria.select(root);
        return entityManager.createQuery(criteria).getResultList();
    }
}

当我在 Main 类中运行代码时,它会加入实体:

主要

ApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring.xml");
UserDao userDao = (UserDao) context.getBean("userDao");
DepartmentDao departmentDao = (DepartmentDao) context.getBean("departmentDao");

Department newDep = new Department("WebDepartment", new Date());
departmentDao.save(newDep);

User newUser1 = new User("Test1", newDep);
User newUser2 = new User("Test2", newDep);
userDao.save(newUser1);
userDao.save(newUser2);

List<Department> deps = departmentDao.getAllWithUsers();

//deps
//[Department{name='WebDepartment', users = ['Test1', 'Test2']}]

当我使用相同的代码运行单元测试时,部门的用户列表为空:

@ContextConfiguration(locations = "classpath:META-INF/spring-test.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class DaoTests {

    @Autowired
    private DepartmentDao departmentDao;

    @Autowired
    private UserDao userDao;

    @Test
    @Transactional
    public void daoTests() throws NoSuchAlgorithmException {

        Department newDep = new Department("WebDepartment", new Date());
        departmentDao.save(newDep);

        User newUser1 = new User("Test1", newDep);
        User newUser2 = new User("Test2", newDep);
        userDao.save(newUser1);
        userDao.save(newUser2);
        List<Department> deps = departmentDao.getAllWithUsers();

        //deps
        //[Department{name='WebDepartment', users = []}]
    }
}

所以,我的问题是:为什么 EAGER 在 Main 中有效,但在测试中却不行?

【问题讨论】:

  • 不同之处在于您在事务中运行的单元测试
  • 我在一个事务中创建用户实体并尝试将它们放入另一个事务中?我没听错吗?
  • 能否请您展示一下 User 实体的构造函数?

标签: java unit-testing jpa eager-loading


【解决方案1】:

我假设您没有将新用户添加到部门的用户列表中。

您的构造函数必须如下所示:

public User(
            // other fields, 
            Department department) {
   // set all fields.

   department.getUsers().add(this);
}

在 Main 中它正在工作,因为您有两个事务,并且在读取中是在一个单独的事务中,并且 Department 是从 DB 中获取的。

但在单元测试中,它会从用户列表为空的内存中返回部门。

在保存实体之前正确设置关系非常重要。

【讨论】:

  • 是的,它帮助了我。谢谢!但还有一个问题。在单元测试中保存到数据库或从数据库读取会创建真正的事务吗?还是所有对数据的操作都在 java 内存中?
  • 如果你在 SpringRunner 的单元测试中使用 Transactional,那么它会创建一个数据库事务,默认情况下会在测试方法结束时回滚
猜你喜欢
  • 2012-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-26
  • 1970-01-01
  • 1970-01-01
  • 2018-07-12
  • 1970-01-01
相关资源
最近更新 更多