我创建了一个自定义迭代器,该迭代器在其构造函数中接受多个迭代器,并为使用三个迭代器构造的示例生成备用输出:
[a,b,c],[1,2]和[x,y,z]
迭代器应按此顺序生成元素
a,1,x,b,2,y,c,z
我的迭代器代码:
package alternate.iterator;
import java.util.Iterator;
/**Alternates on the given iterators.*/
public class ImprovedAlternateIterator<E> implements Iterator {
/**Stores the iterators which are to be alternated on.*/
private Iterator<E>[] iterators;
/**The index of iterator, which has the next element.*/
private int nextIterator = 0;
/**Initializes a new AlternatingIterator object.
* Stores the iterators in the iterators field.
* Finds the first iterator with an available element.*/
public ImprovedAlternateIterator(Iterator<E> ... iterators) {
this.iterators = iterators;
if (!iterators[0].hasNext())
findNextIterator();
}
@Override
public boolean hasNext() {
return iterators[nextIterator].hasNext();
}
@Override
public Object next() {
E element = iterators[nextIterator].next();
findNextIterator();
return element;
}
/**Steps on iterators, until one has next element.
* It does not step on them infinitely, stops when
* the lastly used iterator is reached.*/
private void findNextIterator() {
int currentIterator = nextIterator;
// Finding iterator with element remaining.
do {
stepNextIterator();
} while (!iterators[nextIterator].hasNext() && nextIterator != currentIterator);
// If it gets around to the same iterator, then there is no iterator with element.
}
/**Increases the nextIterator value without indexing out of bounds.*/
private void stepNextIterator() {
nextIterator = (nextIterator + 1) % iterators.length;
}
}
主类:
package alternate.iterator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ListIterator;
public class MainApplication {
public static <E> void main(String[] args) {
ArrayList<String> list1 = new ArrayList<String>();
list1.addAll(Arrays.asList( "A", "B","C"));
ArrayList<String> list2 = new ArrayList<String>();
list2.addAll(Arrays.asList( "x", "y","z"));
ArrayList<Integer> list3 = new ArrayList<Integer>();
list3.addAll(Arrays.asList(1, 2));
// ListIterator to traverse the list
ListIterator iterator1 = list1.listIterator();
ListIterator iterator2 = list2.listIterator();
ListIterator iterator3 = list3.listIterator();
ImprovedAlternateIterator <E> l = new ImprovedAlternateIterator<E>(iterator1,iterator2,iterator3);
while (l.hasNext()) {
System.out.print(l.next()+ " ");
}
}
}
如何编写测试用例以测试自定义迭代器的hasNext()和next()的功能?
我真的很困惑,不知道要测试什么以及如何编写测试用例。我想了解更多有关测试的信息,如果您能通过编写示例测试用例向我展示,那对我真的很有帮助。
答案 0 :(得分:1)
我将使用“测试优先”(或“测试驱动开发”(TDD))方法。将您的代码放在一边。
写出最短的编译内容(无警告-您遗漏了Iterator
的type参数,并且返回的next
类型是错误的):
package alternate.iterator;
import java.util.*;
/**Alternates on the given iterators.*/
public class ImprovedAlternateIterator<E> implements Iterator<E> {
/**Initializes a new AlternatingIterator object.
* Stores the iterators in the iterators field.
* Finds the first iterator with an available element.*/
public ImprovedAlternateIterator(Iterator<E> ... iterators) {
}
@Override
public boolean hasNext() {
return true;
}
@Override
public E next() {
return null;
}
}
现在编写您最简单的测试。以最简单的方式使代码通过。必要时进行重构。再次检查测试。重复直到完成。
您可能会注意到您的界面不完整,例如,构造函数参数应为Iterator<? extends E>
-无需先进行测试就无需修复。您缺少remove
(很遗憾,它已成为默认方法)。
这不是我通常会首先使用的方法,但是我认为这在这里非常有用。
答案 1 :(得分:0)
以下示例提供了两个使用junit和/或hamcrest的测试案例示例。 Hamcrest有很多好处,但是本质上增加了代码的可读性。值得继续阅读。
从您不想使用的断言中删除断言。
import java.util.List;
import org.junit.Test;
import com.nucleusfinancial.ImprovedAlternateIterator;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertEquals;
public class ImprovedAlternateIteratorTest {
@Test
public void hasNext_returns_next_from_first_iterator() {
ImprovedAlternateIterator iterator = new ImprovedAlternateIterator(List.of("foo").iterator());
// junit
assertEquals(iterator.next(), "foo");
// hamcrest
assertThat(iterator.next(), is("foo"));
}
@Test
public void hasNext_returns_next_from_second_iterator_after_first_iterator_has_been_iterated_over() {
ImprovedAlternateIterator iterator = new ImprovedAlternateIterator(List.of("foo").iterator(), List.of("bar").iterator());
//junit
assertEquals(iterator.next(), "foo");
assertEquals(iterator.next(), "bar");
//hamcrest
assertThat(iterator.next(), is("foo"));
assertThat(iterator.next(), is("bar"));
}
}
关于测试用例,从好的用例开始-它能达到预期的目的吗?考虑边界条件。如果输入的内容太大,太小,为空,为空或为空等,会发生什么情况。确保测试所有分支-代码覆盖工具对此很有用。
答案 2 :(得分:0)
在测试Iterator实现之前,您必须考虑什么是类的公共API 。并涵盖此API的合同。
在您的情况下,您有2种公共方法:hasNext()
,next()
。
我想补充一点,对于任何迭代器实现,hasNext()
应该是幂等的。即使调用1、10或100次,结果也应该相同。
此外,您还必须考虑如何管理测试课程。什么是测试数据,如何从不同的测试用例中访问数据,以及如何在执行测试后释放资源等?
请记住,Junit的执行没有严格的测试执行顺序。
它可以调用
test1()
,test2()
,test3()
或
test2()
,test1()
...
因此,您无法检查next()
:在一种方法中,将检索所有迭代器中的第一个元素,而对于另一种方法中的第二个元素,将进行相同的操作。
以下是一些用于测试迭代器实现的框架示例:
private ImprovedAlternateIterator<Iterator> improvedIterator;
@Before
public void setUp() throws Exception {
ArrayList<String> list1 = Lists.newArrayList("A", "B", "C");
ArrayList<String> list2 = Lists.newArrayList("x", "y", "z");
ArrayList<Integer> list3 = Lists.newArrayList(1, 2);
ListIterator iterator1 = list1.listIterator();
ListIterator iterator2 = list2.listIterator();
ListIterator iterator3 = list3.listIterator();
improvedIterator = new ImprovedAlternateIterator<Iterator>(iterator1, iterator2, iterator3);
}
@After
public void tearDown() throws Exception {
improvedIterator = null;
}
/**
* check that hasNext() is idempotent -> even if you call it 1 or 10 times the result should be the same
*/
@Test
public void testHasNextForAlternateIterator() {
for (int i = 0; i < 20; i++) {
assertTrue(improvedIterator.hasNext());
}
}
/**
* check that next() for iterator
* it should return first element per each iterator
*/
@Test
public void testNextForAlternateIterator() {
String expectedFromFirstIterator = "A";
String expectedFromSecondIterator = "x";
int expectedFromThirdIterator = 1;
assertEquals(expectedFromFirstIterator, improvedIterator.next());
assertEquals(expectedFromSecondIterator, improvedIterator.next());
assertEquals(expectedFromThirdIterator, improvedIterator.next());
String expected2FromFirstIterator = "B";
String expected2FromSecondIterator = "y";
int expected2FromThirdIterator = 2;
assertEquals(expected2FromFirstIterator, improvedIterator.next());
assertEquals(expected2FromSecondIterator, improvedIterator.next());
assertEquals(expected2FromThirdIterator, improvedIterator.next());
// you can omit following section if you don't need to cover it
String expected3FromFirstIterator = "C";
String expected3FromSecondIterator = "z";
assertEquals(expected3FromFirstIterator, improvedIterator.next());
assertEquals(expected3FromSecondIterator, improvedIterator.next());
}
如果测试失败,添加一些有用的信息是非常有用的:
assertEquals(“未检索到第一个迭代器的第一个元素”,应该是实际的);
此外,当从迭代器中检索所有元素或该元素为空时,请考虑否定情况。究竟应退还什么?一些异常或默认值。您也可以添加用于覆盖它们的案例。