java 如何编写单元测试来验证函数是否对其结果进行排序?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17687349/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I write a unit test to verify that a function sorts its result?
提问by f.ardelian
I have a data source from which I can request a list of people that live in a (any) country, and a method which retrieves the people from that data source and sorts them by their name alphabetically. How should I write my unit test to make sure that the sorting part of my method works properly?
我有一个数据源,我可以从中请求居住在(任何)国家/地区的人员列表,以及一种从该数据源中检索人员并按姓名字母顺序对其进行排序的方法。我应该如何编写单元测试以确保我的方法的排序部分正常工作?
This is what my SUT looks like:
这是我的 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;
}
}
And this is what my unit test looks like:
这就是我的单元测试的样子:
@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);
}
What I need to know is if the way I am stubbing the data, running the test and making the assertions is correct, or if there are better ways of doing this.
我需要知道的是,我存根数据、运行测试和做出断言的方式是否正确,或者是否有更好的方法来做到这一点。
My application has a lot of methods to test and a lot of custom sorting algorithms; I implemented all tests to use some 4 values that I stub like that, in a "random" orderwhich I choose when I write the test.
我的应用程序有很多测试方法和很多自定义排序算法;我实现了所有测试,以使用我在编写测试时选择的“随机”顺序使用我存根的一些 4 个值。
Should I just test if the comparators are called? That doesn't seem right to me, because I don't know if they're called for the right data or at the right time in the algorithm that's inside getSortedPeopleForCountry()
. I want to detect situations like this:
我应该测试是否调用了比较器?这对我来说似乎不正确,因为我不知道他们是否在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!
}
Should I leave it like this andadd mock comparators which use the real comparators but also verify that they're being called?
我应该像这样保留它并添加使用真实比较器的模拟比较器,但还要验证它们是否被调用?
Am I doing it right?
我做得对吗?
采纳答案by robjohncox
I think your current test is very good - the tests are realistic, exercising all of the code, and you are mocking out the data source & using dependency injection to supply a mock data source. There is a lot of best practice going on in this test.
我认为您当前的测试非常好 - 测试是现实的,运行了所有代码,并且您正在模拟数据源并使用依赖注入来提供模拟数据源。这个测试中有很多最佳实践。
On the issue of whether you should look to mock the comparators (and therefore make the test on testGetPeopleSortsByPeopleName
a pure unit test), you will definitely get two different opinions here:
关于是否应该模拟比较器(因此在testGetPeopleSortsByPeopleName
纯单元测试中进行测试)的问题,您肯定会在这里得到两种不同的意见:
- A purist would argue that your test is technically an integration test, and that to have proper unit tests you need to adjust your test to use a mock comparator, and then test the comparator separately.
- A pragmatist would argue that your test is already high quality, and that it doesn't matter that it isn't a unit test in the strictest sense. Furthermore, to split this into two separate unit tests may make the test less readable - which I imagine would be the case with the test above if you were to involve mock comparators.
- 纯粹主义者会争辩说,您的测试在技术上是一种集成测试,要进行适当的单元测试,您需要调整测试以使用模拟比较器,然后单独测试比较器。
- 实用主义者会争辩说您的测试已经是高质量的,并且它不是最严格意义上的单元测试并不重要。此外,将其拆分为两个单独的单元测试可能会使测试的可读性降低 - 我想如果您要使用模拟比较器,上面的测试就是这种情况。
My personal opinion is that you should leave it as it is, the fact that you have a high quality, readable test that exercises all the code and effectively asserts your requirements is far more important than worrying about having strictly pure unit tests.
我个人的意见是,你应该保持原样,事实上,你有一个高质量、可读的测试,可以运行所有代码并有效地断言你的需求,这比担心有严格的纯单元测试重要得多。
The only way in which the test looks in need of improvement is the length of the test method - I think a little method extraction could help improve readability and make the test method more expressive. I would aim for something like this:
测试看起来需要改进的唯一方法是测试方法的长度 - 我认为一点方法提取可以帮助提高可读性并使测试方法更具表现力。我的目标是这样的:
@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) {
...
}
回答by netod
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);
}
This code represents an example where ArrayList contaning ObjectA objects is sorted by field date in descending order. We are checking if the member of the list has smaller or equal date from his predecessor.
此代码表示一个示例,其中包含 ObjectA 对象的 ArrayList 按字段日期降序排序。我们正在检查列表中的成员的日期是否小于或等于其前任。
回答by Mukus
Separate the sorting logic from returning the list. So I'd have getPeopleForCountry(String countryName) only return a list whereas a sorted list would be returned from getSortedPeopleForCountry(List ). That way you can test how it works before and after sorting. Also, you might want to override the Equals() method to compare names if that is what you want to go with, but then you'd later want to compare with some other property. That's your call.
将排序逻辑与返回列表分开。所以我让 getPeopleForCountry(String countryName) 只返回一个列表,而一个排序的列表将从 getSortedPeopleForCountry(List ) 返回。这样你就可以测试它在排序之前和之后的工作方式。此外,您可能想要覆盖 Equals() 方法来比较名称,如果这是您想要的,但是您稍后想要与其他一些属性进行比较。那是你的电话。