![](/img/trans.png)
[英]How to get full coverage for Java Code Coverage? Junit test cases
[英]How to write Junit test cases for Comparator code coverage
我有一个使用 Comparator 接口的排序机制,如下所示:
public class SortByEmployeeIdByDesc implements Comparator<Employee> {
public int compare(Employee a, Employee b)
{
return b.getEmpId().compareTo(a.getEmpId());
}
}
这是我的员工类:
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
@Getter
private String empId;
private String empName;
private Date createdTime;
@Getter
private Date lastUpdatedTime;
}
我为上述比较器编写了如下测试用例:
@ExtendWith(MockitoExtension.class)
public void EmployeeSortTest{
@Test
public void sortEmpDescloyeeTest() {
Employee emp1 = new Employee("abc", "test", "2020-10-10", "2010-10-10");
Employee emp2 = new Employee("xyz", "test2", "2022-03-04", "2022-03-04");
List<Employee> sortEmp = new ArrayList<>();
sortEmp.add(emp1);
sortEmp.add(emp2);
Collections.sort(sortEmp, new SortByEmployeeIdByDesc());
assertEquals(emp1, sortEmp.get(1));
}
}
上面的测试用例运行成功,但是当我在 Sonar 中签入时,它并没有覆盖代码。 是否有更好的 Junit 测试方法以使覆盖率增加到至少 90%?
我对语言版本和依赖项做了一些假设并运行您的代码:
您的new Employee(...)
构造函数不起作用,因为您的@AllArgsConstructor
期望Date
对象而不是String
。
假设您使用的是 Java8+,您应该使用LocalDate
而不是Date
。
代码覆盖率产生以下结果。
Employee.java:50%未覆盖的行:
@Builder
@NoArgsConstructor
// omitted for brevity
@Getter
private LocalDate lastUpdatedTime;
SortByEmployeeIdByDesc:100%
要覆盖新行,您应该考虑按如下方式更改测试类(例如):
@ExtendWith(MockitoExtension.class)
class SortByEmployeeIdByDescTest {
private static final LocalDate MIN_CREATED = LocalDate.of(2020, 10, 10);
private static final LocalDate MIN_LASTUPDATED = LocalDate.of(2020, 10, 10);
@Test
void sortEmpDescloyeeTest() {
Employee emp1 = new Employee("abc", "test", MIN_CREATED, MIN_LASTUPDATED);
Employee emp2 = new Employee("xyz", "test2", LocalDate.of(2022, 3, 4), LocalDate.of(2022, 3, 4));
List<Employee> sortEmp = new ArrayList<>();
sortEmp.add(emp1);
sortEmp.add(emp2);
sortEmp.sort(new SortByEmployeeIdByDesc());
assertEquals(emp1, sortEmp.get(1));
}
@Test
void noArgsConstructorTest() {
Employee employee = new Employee();
assertNull(employee.getEmpId());
assertNull(employee.getLastUpdatedTime());
}
@Test
void builderTest() {
Employee expectedEmployee = new Employee("testId", "test", MIN_CREATED, MIN_LASTUPDATED);
Employee employee = Employee.builder()
.empId("testId")
.empName("test")
.createdTime(MIN_CREATED)
.lastUpdatedTime(MIN_LASTUPDATED)
.build();
assertEquals(expectedEmployee.getEmpId(), employee.getEmpId());
assertEquals(expectedEmployee.getLastUpdatedTime(), employee.getLastUpdatedTime());
}
}
因为您只在其中两个字段上声明@Getter
,所以您无法在builderTest
中测试其他字段。
如果要比较所有字段,可以执行以下操作:
在 Employee 上添加@EqualsAndHashCode
注释 -
@Builder @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode // this annotation adds equals and hashCode methods public class Employee // omitted for brevity
更改builderTest
代码如下 -
@Test void builderTest() { Employee expectedEmployee = new Employee("testId", "test", MIN_CREATED, MIN_LASTUPDATED); Employee employee = Employee.builder() .empId("testId") .empName("test") .createdTime(MIN_CREATED) .lastUpdatedTime(MIN_LASTUPDATED) .build(); assertEquals(expectedEmployee, employee); // you now use equals // instead of testing // each field // individually }
两种方法(有或没有@EqualsAndHashCode
注释)都产生 100% 的代码覆盖率。 请记住,除非您的 getter 和 setter 中有逻辑,否则覆盖它们通常被认为是微不足道的,因为您本质上是在测试 Java 赋值,人们可能认为这是可行的。
要测试比较器,第一个想法可能是向列表中添加一些项目,对列表进行排序,然后确保项目已正确排序。
但是,这种方法有一个可怕的缺点:对列表进行排序会执行尽可能少的比较,这与您尝试完成的操作完全相反。 另外,根据排序算法,您根本无法确定比较了哪些组合。
我曾经写过一个ComparatorTester
,它获取一个元素列表,然后将每个元素与每个元素进行比较。 它还确保比较器是自反的、反对称的和传递的。
当我在 Google 上搜索 ComparatorTester 时,我发现Firebase 的一个实现与我自己的实现非常相似,因为它使用了完全相同的想法。 这就是你应该遵循的方法。
在您的琐碎用例中,您甚至不需要编写自己的比较器类,这是 Java 8 之前的事情。如今,按单个属性排序变成了单线:
employees.sort(Comparator.comparing(Employee::getEmpId).reversed());
Comparator.compare(T o1, T o2)
javadoc 状态(强调添加):
返回:负整数、零或正整数,因为第一个参数小于、等于或大于第二个参数。
因此,您的测试至少需要涵盖上述三个条件:
class SortByEmployeeIdByDescTest {
@Test
void compareEmployees() {
final List<Employee> employees = Stream.of("2", "1", "3", "2")
.map(id -> Employee.builder().empId(id).build())
.collect(Collectors.toList());
Collections.sort(employees, new SortByEmployeeIdByDesc());
assertThat(employees).extracting(Employee::getEmpId)
.containsExactly("3", "2", "2", "1");
}
}
我在此示例中使用AssertJ ,强烈建议在您的项目中使用它。
此外,您的员工 ID 是一个字符串。 因此,您需要测试它何时为null
。 然后您将获得所需的覆盖范围。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.