原文: https://javatutorial.net/how-to-unit-test-dao-components
在本教程中,您将学习如何为 DAO 创建单元测试。 前提条件是,您需要具备 DAO 的基本知识。
在测试 DAO 组件时,我们确实有两种方法。一种是使用模拟框架Mockito
,另一种是创建两个可以协同工作的类。
在本教程中,我们将使用Mockito
。
EmployeeDAO
public class EmployeeDAO implements Dao<Employee> {
// will act as a "mini-database"
private List<Employee> employees = new ArrayList<>();
private SessionFactory sessFactory;
// Constructor
public EmployeeDAO(SessionFactory s) {
// Populate our list of employees with 3 Demos
employees.add(new Employee("Demo1", "Demo1@example.com"));
employees.add(new Employee("Demo2", "Demo2@example.com"));
employees.add(new Employee("Demo3", "Demo3@example.com"));
sessFactory = s;
}
// Overriding the Dao interface methods
@Override
public Employee get(long id) {
return employees.get((int) id));
}
@Override
public List<Employee> getAll() {
return employees;
}
@Override
public void save(Employee emp) {
employees.add(emp);
}
@Override
public void update(Employee employee, String[] params) {
// Check for validity
if (params[0].length() != 0|| params[1].length() != 0) {
// Initialize the employee
employee.setName(params[0]);
employee.setEmail(params[1]);
// Add the Initialized employee to the list of employees (a.k.a. DB)
employees.add(employee);
}
}
@Override
public void delete(Employee employee) {
employees.remove(employee);
}
}
如果您想知道Employee
类的外观,则为:
Employee.java
public class Employee {
//members
private String name;
private String email;
// constructor
Employee(String n, String e) {
name = n;
email = e;
}
// setter methods
public void setName(String n) {
name = n;
}
public void setEmail(String e) {
email = e;
}
// getter methods
public String getName() {
return name;
}
public String getEmail() {
return email;
}
}
雇员类只是一个标准的构造器/获取器/设置器方法。
现在是时候为 DAO 类创建测试类了。
EmployeeDAOTest
@ExtendWith(SpringExtension.class)
@Tag("DAO")
public class EmployeeDAOTest {
@MockBean
private SessionFactory sessionFactory;
@MockBean
private Session session;
private EmployeeDAO employeeDAO;
@BeforeEach
public void prepare() throws Exception {
Mockito.when(sessionFactory.getCurrentSession()).thenReturn(session);
employeeDAO = new EmployeeDAO(sessionFactory);
}
@Test
public void should_returnNull_ifNonExistent() {
Query q = Mockito.mock(Query.class);
Mockito.when(session.getNamedQuery("get")).thenReturn(q);
Mockito.when(q.getResultList()).thenReturn(new ArrayList());
List l = employeeDAO.getAll();
assertAll("Employees",
() -> assertNotEquals(l, null),
() -> assertEquals(l.size(), 0));
}
}
细分
在上一课中有两件事需要分解。
首先,请注意,我们使用的@MockBean 注解只是将模拟对象添加到应用程序上下文中。 这意味着它将替换任何现有的相同类型的 bean。 如果没有现有的 bean,将创建一个新的 bean。
然后,我们使用@BeforeEach
注解,该注解将在所有单元测试运行之前执行。 因此,该方法的名称为prepare
,我们正在为单元测试准备“环境”。
在prepare
方法中,我们有两件事。 由于SessionFactory
是一个功能接口,因此可以将其用作 lambda 表达式的分配。
我们在prepare()
方法中使用Mockito.when
方法。 它用于在调用过程中给出异常的模拟方法。 所以线
Mockito.when(sessionFactory.getCurrentSession()).thenReturn(session);
确实是在说“让我获得当前会话,如果没有异常,请给我返回该会话”。 然后,我们只需将 DAO 实例分配给一个全新的实例:
employeeDAO = new EmployeeDAO(sessionFactory);
之后,我们就有了测试目标方法,称为should_returnNull_ifNonExistent()
,它的名称如实:返回null
,如果没有则返回空的ArrayList
要返回的列表。 但是在EmployeeDAO
实现中,我们永远不会冒为空的风险,因为一旦创建EmployeeDAO()
实例,我们便在列表中添加了三个Employee
条目:
public EmployeeDAO(SessionFactory s) {
// Populate our list of employees with 3 Demos
employees.add(new Employee("Demo1", "Demo1@example.com"));
employees.add(new Employee("Demo2", "Demo2@example.com"));
employees.add(new Employee("Demo3", "Demo3@example.com"));
sessFactory = s;
}
注意方法的@Test
注解。 这指定此方法用于测试目的。 我们在EmployeeDAO
类中获得了被我们覆盖的get
方法,如果没有异常,则返回q
类型的查询。 然后我们简单地返回一个新的空数组列表。
之后,我们使用getAll()
方法至少应返回 3 个条目,然后使用assertAll()
方法,该方法结合了assertNotEquals
和assertEquals
。 这些行:
assertAll("Employees",
() -> assertNotEquals(l, null),
() -> assertEquals(l.size(), 0));
确实是在说检查l
(包含从getAll()
方法返回的条目的列表)是否为空,并检查列表的大小是否为 0。如果是,则返回true
,assertEquals
的评估结果为true
。