对于我的课程,我们正在创建ArrayStacks和LinkedStacks,而不是使用J-Unit进行测试。我们的一个测试是在clear()方法上。我们的教授明确要求我们将堆栈中的每个元素都清零,然后测试它们是否为空。我该怎么做?
public void clear() {
// Checks if this stack is empty,
// otherwise clears this stack.
if(!isEmpty()){
for(int i = 0; i < sizeIs(); i++){
pop();
}
topIndex = -1;
}
}
public class Test_clear {
/*
* Class to test the clear method added to the Stack ADT of Lab04
*
* tests clear on an empty stack
* a stack with one element
* a stack with many (but less than full) elements
* and a "full" ArrayStack (not applicable to Linked Stack - comment it out)
*/
ArrayStack stk1, stk2;
@Before
public void setUp() throws Exception {
stk1 = new ArrayStack(); stk2 = new ArrayStack();
}
@Test
public void test_clear_on_an_emptyStack() {
stk1.clear();
Assert.assertEquals(true, stk1.isEmpty());
}
@Test
public void test_clear_on_a_stack_with_1_element() {
stk1.push(5);
stk1.clear();
Assert.assertEquals(true, stk1.isEmpty())'
}
等等。但是检查isEmpty()上的assertEquals将不会测试我的数组中的元素是否被清除。提前谢谢!
答案 0 :(得分:3)
为了测试数组是否正确地将对从堆栈弹出的元素的引用归零,你必须有一些方法在测试期间直接访问数组。
也许有一个包私有方法来返回(一个防御性的副本)支持数组?
答案 1 :(得分:2)
虽然从学习Java的来龙去脉的角度来看这种练习是值得的,但我会建议在将其应用于其他问题之前谨慎。
鼓励使用JUnit来练习您所测试类的公共接口。在ArrayStack
的情况下,让我们假设它有几个方法:
void push(Object o)
Object pop()
void clear()
@dkaztzel提出了一个解决方案 - 实现一个包私有方法来防御性地复制内部堆栈的内容。让我们说它看起来像这样:
Object[] getStack() {
return stack.clone();
}
假设您已经实现了一些单元测试以验证push
和pop
是否按预期工作(包括空堆栈和完整堆栈的边缘情况),那么您将创建单元测试如下:
@Test
public void probablyNotAGoodTest() {
ArrayStack arrayStack = new ArrayStack();
arrayStack.push("Luke");
arrayStack.clear();
Object[] stackCopy = arrayStack.getStack();
assertNull(stackCopy[0]);
}
这实现了验证实际上在弹出元素后将索引的值设置为null的意图。当我必须编写生产代码时,我总是有点可疑,其唯一目的是帮助我测试我的合同。并不是说这种方法是错误的,而是需要仔细考虑。这里的要求是确保弹出的对象实际上从内部堆栈中删除,所以也许这没关系。
另一种方法是丰富ArrayStack
接口,并提供一种方法来检索给定索引处的特定对象。如果遇到null对象,此方法可能会抛出异常,然后您可以测试它。这是方法和测试的样子(请在使用之前进行一些额外的验证):
public Object getObjectAtIndex(int i) {
if (i >= maxSize) {
throw new IllegalArgumentException();
}
if (stack[i] == null) {
throw new NullPointerException();
}
return stack[i];
}
然后测试:
@Test(expected=NullPointerException.class)
public void tryToGetAClearedObject() {
ArrayStack arrayStack = new ArrayStack();
arrayStack.push("Luke");
arrayStack.clear();
arrayStack.getObjectAtIndex(0);
}
祝你好运!
答案 2 :(得分:0)
正如其他答案所示,null
存储阵列无法通过公共API直接验证。最简单的方法是添加protected
方法以允许直接检查存储。
作为替代方案,请考虑此功能的原因:在调用clear
时,应释放数组中保存的任何引用。您可以仅使用公共API,Reference
和一些关于GC的假设(Is there a way to FORCE weak and/or soft referenced objects to be GC'd in Java?)对此进行测试。
将对象放在堆栈上,保留Reference
,然后clear
:
ReferenceQueue queue = new ReferenceQueue();
PhantomReference ref = addObjectToStackAndCreateReference(arrayStack, queue);
arrayStack.clear()
使用单独的实用程序方法将该对象保留在Java堆栈之外,这可能会阻止收集:
private static PhantomReference addObjectToStackAndCreateReference(ArrayStack arrayStack, ReferenceQueue queue)
{
Object o = new Object();
PhantomReference ref = new PhantomReference(o, queue);
arrayStack.push(o);
return ref;
}
现在,验证对象没有剩余的引用,因此引用已入队:
System.gc();
assertSame(ref, queue.remove());
我建议添加方法以使测试更简单;但是,这是一种可以在不添加任何仅测试API的情况下进行测试的方法。