2

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

4

3 回答 3

3

为了测试数组是否正确地清空了对从堆栈中弹出的元素的引用,您必须有一些方法可以在测试期间直接访问数组。

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

于 2013-09-26T20:36:04.187 回答
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接口,并提供一种在给定索引处检索特定对象的方法。如果遇到空对象,此方法可能会引发异常,然后您可以对其进行测试。下面是方法和测试的样子(请在使用之前做一些额外的验证):

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

祝你好运!

于 2013-10-01T05:39:08.160 回答
0

正如其他答案所暗示null的那样,公共API无法直接验证存储阵列。添加一种protected允许直接检查存储的方法是最简单的。

作为替代方案,请考虑使用此功能的原因:数组中保存的任何引用都应在clear调用时释放。您可以仅使用公共 API、References 和一些关于 GC 的假设来测试这一点(Is there a way to FORCE weak and/or soft referenced objects to be GC'd in Java?)。

将一个对象放在堆栈上,保留 a 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 即可对其进行测试的方法。

于 2013-10-05T09:06:13.537 回答