2

For my class we are creating ArrayStacks and LinkedStacks, than practicing testing with J-Unit. One of our tests is on the clear() method. Our professor specifically asked that we null out each element in our stacks, and than test that they are null. How do I do this?

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())'
}

and so on. But checking assertEquals on isEmpty() won't test if the elements in my array are cleared or not. Thanks in advance!

  • The array is `private`, or should be. So see also http://stackoverflow.com/questions/34571/whats-the-proper-way-to-test-a-class-with-private-methods-using-junit – Raedwald Oct 05 '13 at 09:57

3 Answers3

3

Inorder to test if the array is correctly nulling out references to the elements popped from the stack, you will have to have some way to directly access the array during tests.

Maybe have a package private method to return (a defensive copy of) the backing array?

dkatzel
  • 31,188
  • 3
  • 63
  • 67
2

While this kind of exercise is worthwhile from the perspective of learning the ins and outs of Java, I would advise caution before applying this to other problems.

It's encouraged to use JUnit to exercise the public interface of your class under test. In the case of ArrayStack, let's assume it has a few methods:

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

@dkaztzel suggested one solution - to implement a package private method to defensively copy the contents of your internal stack. Let's say it looks like this:

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

Assuming you've implemented a few unit tests to verify that push and pop are working as intended (including the edge cases of empty and full stacks), then you would create a unit test as follows:

@Test
public void probablyNotAGoodTest() {
    ArrayStack arrayStack = new ArrayStack();
    arrayStack.push("Luke");

    arrayStack.clear();

    Object[] stackCopy = arrayStack.getStack();
    assertNull(stackCopy[0]);
}

This achieves your intent of verifying that in fact you've set the value at the index to null once an element has been popped. I'm always a little suspicious when I have to write production code whose sole purpose is to help me test my contract. Not to say that this approach is wrong, but that it requires careful consideration. Here the requirement is to ensure that popped objects are actually removed from the internal stack, so maybe this is okay.

Another approach would be to enrich the ArrayStack interface, and provide a method to retrieve a particular object at a given index. This method could throw an exception if a null object is encountered, and then you could test for that. Here's what the method and a test could look like (please do some additional verification before you use this):

public Object getObjectAtIndex(int i) {
    if (i >= maxSize) {
        throw new IllegalArgumentException();
    }
    if (stack[i] == null) {
        throw new NullPointerException();
    }

    return stack[i];
}

And then the test:

@Test(expected=NullPointerException.class) 
public void tryToGetAClearedObject() {
    ArrayStack arrayStack = new ArrayStack();
    arrayStack.push("Luke");
    arrayStack.clear();
    arrayStack.getObjectAtIndex(0);
}

Good luck!

Meesh
  • 379
  • 1
  • 13
0

As other answers suggest, nulling out the storage array is not directly verifiable by the public API. It would be simplest to add a protected method to allow direct examination of storage.

As an alternative, consider the reason for this feature: any references held in your array should be released when clear is called. You can test this using only the public API, References and some assumptions about GC (Is there a way to FORCE weak and/or soft referenced objects to be GC'd in Java?).

Place an object on the stack, retaining a Reference, and then clear it:

ReferenceQueue queue = new ReferenceQueue();
PhantomReference ref = addObjectToStackAndCreateReference(arrayStack, queue);

arrayStack.clear()

with a separate utility method to keep that object off the Java stack, which could prevent collection:

private static PhantomReference addObjectToStackAndCreateReference(ArrayStack arrayStack, ReferenceQueue queue)
{
    Object o = new Object();
    PhantomReference ref = new PhantomReference(o, queue);
    arrayStack.push(o);
    return ref;
}

Now, verify that there are no remaining references to the object, so the reference has been enqueued:

System.gc();
assertSame(ref, queue.remove());

I'd recommend adding methods to make the testing simpler; however, that's one way you could test it without adding any test-only API.

Community
  • 1
  • 1
Joe
  • 29,416
  • 12
  • 68
  • 88