J-Unit测试数组堆栈中的clear()方法

时间:2013-09-26 20:29:57

标签: java junit

对于我的课程,我们正在创建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将不会测试我的数组中的元素是否被清除。提前谢谢!

3 个答案:

答案 0 :(得分:3)

为了测试数组是否正确地将对从堆栈弹出的元素的引用归零,你必须有一些方法在测试期间直接访问数组。

也许有一个包私有方法来返回(一个防御性的副本)支持数组?

答案 1 :(得分:2)

虽然从学习Java的来龙去脉的角度来看这种练习是值得的,但我会建议在将其应用于其他问题之前谨慎

鼓励使用JUnit来练习您所测试类的公共接口。在ArrayStack的情况下,让我们假设它有几个方法:

  
      
  • void push(Object o)
  •   
  • Object pop()
  •   
  • void clear()
  •   

@dkaztzel提出了一个解决方案 - 实现一个包私有方法来防御性地复制内部堆栈的内容。让我们说它看起来像这样:

Object[] getStack() {
    return stack.clone();
}

假设您已经实现了一些单元测试以验证pushpop是否按预期工作(包括空堆栈和完整堆栈的边缘情况),那么您将创建单元测试如下:

@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的情况下进行测试的方法。