如何为基于字符串条件从数组中过滤元素的方法编写测试

How to write a test for a method which is filtering elements from an array based on string criteria

我有一个 Car class 的类别字段是 String:

public class Car {

     private String category;

     public Car(String category) {
         this.category = category;
     }

     public String getCategory() {
         return category;
     }

     public void setCategory(String category) {
         this.category = category;
     }
}

我有这个方法,它使用 contains() 方法过滤掉基于 String 的数组中的元素,只保留跑车。我知道这是个坏主意,只是想写我的第一个单元测试。你能帮我理解从哪里开始吗?一般来说,测试循环过滤逻辑的最佳实践是什么。

private List<Car> filterOutEverythingExceptSportCars(List<Car> cars) {
    List<Car> filteredCarsList = new ArrayList<>();

    for (int i = 0; i < cars.size(); i++) {
        if (cars.get(i).getCategory().contains("sport")) {
            filteredCarsList.add(cars.get(i));
        }
    }
    return filteredCarsList;
}

您可以查看 Stream 并像这样使用过滤器运算符。

private static List<Car> filterOutSportCars(List<Car> cars) {
   return cars.stream().filter(car -> !car.category.contains("sport")).collect(Collectors.toList());

}

只需测试合约 - 如果您输入 <something>,那么您期望返回什么?例如,如果我调用 filterOutEverythingExceptSportsCars(null)filterOutEverythingExceptSportsCars(Collections.emptyList())filterOutEverythingExceptSportsCars(Arrays.asList(car1, null, car2))

会发生什么

然后围绕这一系列先决条件、操作和预期结果构建测试。所以你的第一个测试可能是:

@Test
givenListOfCarsIsNull_whenFilteringOutEverythingExceptSportsCars_thenReturnEmptyList() {
    final List<Car> in = null; //precondition
    final List<Car> out = filterOutEverythingExceptSportsCars(in); //calling the method
    assertTrue(out.isEmpty()); //verifying expected output
}

如果您希望在这种情况下返回一个空列表。相反,您可能期望抛出异常或其他东西。

首先,您需要使您的方法可测试。在您的实现中,它是一个私有实例方法。由于您没有使用实例中的任何其他内容,因此可以将其设为包私有静态方法:

static List<Car> filterOutEverythingExceptSportCars(List<Car> cars) {
    List<Car> filteredCarsList = new ArrayList<>();
    for (Car car: cars) {
        if (!car.getCategory().contains("sport")) {
            filteredCarsList.add(car);
        }
    }
    return filteredCarsList;
}

现在您可以轻松编写带有要比较的输入和输出列表的单元测试:

@Test
public static void testFilterOutEverythingExceptSportCars() {
    List<Car> cars = ...;
    List<Car> actual = filterOutEverythingExceptSportCars(cars);
    List<Car> expected = ...;
    assertEquals(expected, actual);
}

您只需要静态导入 filterOutEverythingExceptSportCars 方法并将测试 class 放在与实现相同的包中。

请注意,for-loop 的改进取决于您申请,而不是强制性的。我也没有更改命名或 if-condition 以匹配。只需编写您的测试并迭代您的实现,直到您最喜欢它...

也许你想尝试 kotlin(编译成 java 字节码):

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test

class Car(var category: String)

fun sportCars(list: List<Car>) = list.filter { it.category.contains("sport") }

class CarTests {
    @Test
    fun `one ferrari and one truck`() {
        val ferrari = Car("ferrarisportcar")
        val truck = Car("truck")

        val sportCars = sportCars(listOf(ferrari, truck))

        assertThat(sportCars).containsOnly(ferrari)
    }
}

您可以混合使用 kotlin 和 java。因此,一个选项可能是使用 java 作为生产代码,使用 kotlin 作为测试代码。