原文: https://javatutorial.net/how-to-unit-test-dao-components

    在本教程中,您将学习如何为 DAO 创建单元测试。 前提条件是,您需要具备 DAO 的基本知识。

    如何对 DAO 组件进行单元测试 - 图1

    在测试 DAO 组件时,我们确实有两种方法。一种是使用模拟框架Mockito ,另一种是创建两个可以协同工作的类。

    在本教程中,我们将使用Mockito

    EmployeeDAO

    1. public class EmployeeDAO implements Dao<Employee> {
    2. // will act as a "mini-database"
    3. private List<Employee> employees = new ArrayList<>();
    4. private SessionFactory sessFactory;
    5. // Constructor
    6. public EmployeeDAO(SessionFactory s) {
    7. // Populate our list of employees with 3 Demos
    8. employees.add(new Employee("Demo1", "Demo1@example.com"));
    9. employees.add(new Employee("Demo2", "Demo2@example.com"));
    10. employees.add(new Employee("Demo3", "Demo3@example.com"));
    11. sessFactory = s;
    12. }
    13. // Overriding the Dao interface methods
    14. @Override
    15. public Employee get(long id) {
    16. return employees.get((int) id));
    17. }
    18. @Override
    19. public List<Employee> getAll() {
    20. return employees;
    21. }
    22. @Override
    23. public void save(Employee emp) {
    24. employees.add(emp);
    25. }
    26. @Override
    27. public void update(Employee employee, String[] params) {
    28. // Check for validity
    29. if (params[0].length() != 0|| params[1].length() != 0) {
    30. // Initialize the employee
    31. employee.setName(params[0]);
    32. employee.setEmail(params[1]);
    33. // Add the Initialized employee to the list of employees (a.k.a. DB)
    34. employees.add(employee);
    35. }
    36. }
    37. @Override
    38. public void delete(Employee employee) {
    39. employees.remove(employee);
    40. }
    41. }

    如果您想知道Employee类的外观,则为:

    Employee.java

    1. public class Employee {
    2. //members
    3. private String name;
    4. private String email;
    5. // constructor
    6. Employee(String n, String e) {
    7. name = n;
    8. email = e;
    9. }
    10. // setter methods
    11. public void setName(String n) {
    12. name = n;
    13. }
    14. public void setEmail(String e) {
    15. email = e;
    16. }
    17. // getter methods
    18. public String getName() {
    19. return name;
    20. }
    21. public String getEmail() {
    22. return email;
    23. }
    24. }

    雇员类只是一个标准的构造器/获取器/设置器方法。

    现在是时候为 DAO 类创建测试类了。

    EmployeeDAOTest

    1. @ExtendWith(SpringExtension.class)
    2. @Tag("DAO")
    3. public class EmployeeDAOTest {
    4. @MockBean
    5. private SessionFactory sessionFactory;
    6. @MockBean
    7. private Session session;
    8. private EmployeeDAO employeeDAO;
    9. @BeforeEach
    10. public void prepare() throws Exception {
    11. Mockito.when(sessionFactory.getCurrentSession()).thenReturn(session);
    12. employeeDAO = new EmployeeDAO(sessionFactory);
    13. }
    14. @Test
    15. public void should_returnNull_ifNonExistent() {
    16. Query q = Mockito.mock(Query.class);
    17. Mockito.when(session.getNamedQuery("get")).thenReturn(q);
    18. Mockito.when(q.getResultList()).thenReturn(new ArrayList());
    19. List l = employeeDAO.getAll();
    20. assertAll("Employees",
    21. () -> assertNotEquals(l, null),
    22. () -> assertEquals(l.size(), 0));
    23. }
    24. }

    细分

    在上一课中有两件事需要分解。

    首先,请注意,我们使用的@MockBean 注解只是将模拟对象添加到应用程序上下文中。 这意味着它将替换任何现有的相同类型的 bean。 如果没有现有的 bean,将创建一个新的 bean。

    然后,我们使用@BeforeEach注解,该注解将在所有单元测试运行之前执行。 因此,该方法的名称为prepare,我们正在为单元测试准备“环境”。

    prepare方法中,我们有两件事。 由于SessionFactory是一个功能接口,因此可以将其用作 lambda 表达式的分配。

    我们在prepare()方法中使用Mockito.when方法。 它用于在调用过程中给出异常的模拟方法。 所以线

    1. Mockito.when(sessionFactory.getCurrentSession()).thenReturn(session);

    确实是在说“让我获得当前会话,如果没有异常,请给我返回该会话”。 然后,我们只需将 DAO 实例分配给一个全新的实例:

    1. employeeDAO = new EmployeeDAO(sessionFactory);

    之后,我们就有了测试目标方法,称为should_returnNull_ifNonExistent(),它的名称如实:返回null,如果没有则返回空的ArrayList要返回的列表。 但是在EmployeeDAO实现中,我们永远不会冒为空的风险,因为一旦创建EmployeeDAO()实例,我们便在列表中添加了三个Employee条目:

    1. public EmployeeDAO(SessionFactory s) {
    2. // Populate our list of employees with 3 Demos
    3. employees.add(new Employee("Demo1", "Demo1@example.com"));
    4. employees.add(new Employee("Demo2", "Demo2@example.com"));
    5. employees.add(new Employee("Demo3", "Demo3@example.com"));
    6. sessFactory = s;
    7. }

    注意方法的@Test注解。 这指定此方法用于测试目的。 我们在EmployeeDAO类中获得了被我们覆盖的get方法,如果没有异常,则返回q类型的查询。 然后我们简单地返回一个新的空数组列表。

    之后,我们使用getAll()方法至少应返回 3 个条目,然后使用assertAll()方法,该方法结合了assertNotEqualsassertEquals。 这些行:

    1. assertAll("Employees",
    2. () -> assertNotEquals(l, null),
    3. () -> assertEquals(l.size(), 0));

    确实是在说检查l(包含从getAll()方法返回的条目的列表)是否为空,并检查列表的大小是否为 0。如果是,则返回trueassertEquals的评估结果为true