[英]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.