簡體   English   中英

如何為 Comparator 代碼覆蓋率編寫 Junit 測試用例

[英]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%?

我對語言版本和依賴項做了一些假設並運行您的代碼:

  • Java 8+(語言 8 級)
  • JUnit 5(木星)

您的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中測試其他字段。

如果要比較所有字段,可以執行以下操作:

  1. 在 Employee 上添加@EqualsAndHashCode注釋 -

     @Builder @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode // this annotation adds equals and hashCode methods public class Employee // omitted for brevity
  2. 更改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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM