2013-07-16 75 views
5

我有一个数据源,我可以从中请求一个居住在任何国家的人的列表,以及一种从该数据源中检索人并按字母顺序排列他们的方法。我应该如何编写单元测试以确保我的方法的排序部分正常工作?如何编写单元测试来验证函数对结果进行排序?

这是我的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; 
    } 

} 

这是我的单元测试是什么样子:

@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); 
} 

我需要知道的是,如果这样我磕碰数据,运行测试并做出断言是正确的,或者是否有更好的方法来做到这一点。

我的应用程序有很多方法来测试和很多自定义排序算法;我实施了所有测试,以使用4个我喜欢的测试值,in a "random" order,这是我在编写测试时选择的值。


我应该只测试比较器是否被调用?这对我来说并不合适,因为我不知道他们是否需要正确的数据或在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! 
} 

我应该把它像这样增加其使用真正的比较也证实他们被称为模拟比较器?

我在做对吧?

+0

我会对列表进行排序,然后开始比较其中的元素,以确保* current *元素与前一个元素具有相同或更大的*国家。 –

+0

@LuiggiMendoza我已经做到了,但我改变了主意。这在测试中添加了对'PersonNameComparator'的依赖。它采用了3行的“for”循环,这意味着测试中的额外算法,阅读者必须理解这些算法才能理解测试。 –

+0

你让它看起来像3行代码很难理解......实际上,因为我不使用easymock,所以上面的代码对于我来说比使用简单的for循环更难以理解。 'if'。 –

回答

2

我认为你目前的测试非常好 - 测试是现实的,行使所有的代码,并且你正在使用依赖注入模拟出数据源&来提供一个模拟数据源。在这个测试中有很多最佳实践。

在你是否应该嘲笑比较(并因此使测试上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) { 
    ... 
} 
+0

好吧,所以我就这样做了,最后得到了大量的存根生成方法和列表断言方法,但是结果很好,因为我只是将它们全部放在测试帮助程序文件中。测试看起来非常整齐,易于维护。谢谢。 –

1

将排序逻辑与返回列表分开。所以我有getPeopleForCountry(String countryName)只返回一个列表,而排序列表将从getSortedPeopleForCountry(List)返回。这样你就可以在排序前后测试它的工作原理。另外,如果这是你想要的,你可能想要重写Equals()方法来比较名称,但是之后你想要与其他属性进行比较。这是你的电话。

+0

这是非常模糊的,它完全忽略了我写我有Person对象的自定义比较器。而且,这个代码只是我开发中的一个虚拟版本。问题是关于如何测试函数_looks like_我写的例子是对给定的数据进行排序。 –

+0

它如何忽略你写的比较器?您的比较器将在我的答案中使用getSortedPeopleForCountry(List T)...。无论如何,这是我的代码。如果你有像testGetPeopleForCountryWhenNotSorting()这样的测试方法,你可以测试其他的非排序方法不会测试。 – Mukus

0
ObjectA[] arr = objectAList.toArray(new ObjectA[objectAList.size()]); 
for (int i = 0; i < objectAList.size() - 1; i++) { 
     int j = i + 1; 
     assertTrue(arr[i].getDate().compareTo(arr[j].getDate()) >= 0); 
} 

这个代码表示,其中的ArrayList contaning对象A的对象是通过实地日期降序排列的例子。我们正在检查名单上的成员是否与他的前任有较小或相等的日期。

相关问题