如何编写单元测试以验证函数是否对其结果进行排序?

f.a*_*ian 8 java junit unit-testing easymock

我有一个数据源,我可以从中请求一个(任何)国家/地区的人员列表,以及一个从该数据源检索人员并按字母顺序按名称对其进行排序的方法.我应该如何编写单元测试以确保我的方法的排序部分正常工作?

这就是我的SUT的样子:

class PeopleStuff {

    public IData data;

    public List<Person> getSortedPeopleForCountry(String countryName) {
        List<Person> people = data.getPeopleForCountry(countryName);

        Comparator nameComparator = new PersonNameComparator();
        Collections.sort(people, nameComparator);

        return people;
    }

}
Run Code Online (Sandbox Code Playgroud)

这就是我的单元测试的样子:

@Test public void testGetPeopleSortsByPeopleName() {
    String COUNTRY = "Whatistan";

    // set up test (the 3 lines below are actually in a @Before setup method)
    PeopleStuff peopleStuff = new PeopleStuff();
    IData mockData = createNiceMock(IData.class);
    peopleStuff.data = mockData;

    // set up data
    List<PersonName> mockPeopleList = new ArrayList<PersonName>();
    mockPeopleList.add(new Person(COUNTRY, "A"));
    mockPeopleList.add(new Person(COUNTRY, "D"));
    mockPeopleList.add(new Person(COUNTRY, "B"));
    mockPeopleList.add(new Person(COUNTRY, "C"));

    when(mockData.getPeopleForCountry(COUNTRY)).thenReturn(mockPeopleList);

    // exercise
    List<String> result = peopleStuff.getSortedPeopleForCountry(COUNTRY);

    // assert
    assertEquals("A", result.get(0).name);
    assertEquals("B", result.get(1).name);
    assertEquals("C", result.get(2).name);
    assertEquals("D", result.get(3).name);
}
Run Code Online (Sandbox Code Playgroud)

我需要知道的是,我是如何对数据进行存根,运行测试并使断言正确,或者是否有更好的方法来执行此操作.

我的应用程序有很多测试方法和很多自定义排序算法; 我实现了所有的测试,使用我编写的4个值,这是我在编写测试时选择的"随机"顺序.


我应该测试比较器是否被调用?这对我来说似乎不对,因为我不知道他们是否需要正确的数据,或者是在内部算法的正确时间getSortedPeopleForCountry().我想检测这样的情况:

public List<Person> getSortedPeopleForCountry(String countryName) {
    List<Person> people = data.getPeopleForCountry(countryName);

    Comparator nameComparator = new PersonNameComparator();
    List<Person> sortedPeople = new ArrayList<Person>(people)
    Collections.sort(sortedPeople, nameComparator);

    return people; // oops!
}
Run Code Online (Sandbox Code Playgroud)

我应该像这样离开它添加使用真实比较器的模拟比较器,但也要验证它们是否被调用?

我做得对吗?

rob*_*cox 5

我认为您当前的测试非常好 - 测试是现实的,执行了所有代码,并且您正在模拟数据源并使用依赖项注入来提供模拟数据源。此测试中有很多最佳实践。

关于是否应该模拟比较器(从而在testGetPeopleSortsByPeopleName纯单元测试上进行测试)的问题,您肯定会在这里得到两种不同的意见:

  • 纯粹主义者会认为您的测试在技术上是集成测试,并且要进行适当的单元测试,您需要调整测试以使用模拟比较器,然后单独测试比较器。
  • 实用主义者会认为您的测试已经是高质量的,并且它不是最严格意义上的单元测试并不重要。此外,将其分成两个单独的单元测试可能会使测试的可读性降低 - 我想如果您要涉及模拟比较器,上面的测试就会出现这种情况。

我个人的观点是,您应该保持原样,事实上,您拥有一个高质量、可读的测试来执行所有代码并有效地断言您的需求,这比担心严格的纯单元测试重要得多。

测试看起来需要改进的唯一方式是测试方法的长度 - 我认为一点方法提取可以帮助提高可读性并使测试方法更具表现力。我的目标是这样的:

@Test public void testGetPeopleSortsByPeopleName() {

    peopleStuff.data = buildMockDataSource(COUNTRY, "A", "D", "B", "C")

    List<String> result = peopleStuff.getSortedPeopleForCountry(COUNTRY);

    assertPersonList(result, "A", "B", "C", "D")
}

private IData buildMockDataSource(String country, String ... names) {
    ...
}

private void assertPersonList(List<Person> people, String ... names) {
    ...
}
Run Code Online (Sandbox Code Playgroud)