Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access rights of fields regarding JUnit tests

Suppose I have a class which implements a stack in the style of a linked list:

public class Stack {
    private StackNode base;

    public void push(Object item) {
        if (base == null) {base = new StackNode(item);}
        // remaining implementation not shown
    }
}

and a JUnit test class for it:

public class TestStack {
    @Test
    public void testPush() {
        Stack st = new Stack();
        st.push(new Integer(3)); 

        assertEquals((Integer)st.base.getContents(), new Integer(3)); //Error!
        // other test cases not shown
    }
}

My question is: what is the best practice for solving the issue of the test class's access rights to base?

I am aware of this question which discusses making an accessor, and I know that I could also put my Stack and TestStack code into a package and make the base field package-private.

I'm wondering what the best course of action is. I know I shouldn't be using pop in push's unit test, and vice versa, as this couples those unit tests.

I think that making a (public) accessor is bad practice if I don't want client code to access the field, so is the right call to make an accessor for the field (or the field itself) package-private?

Another informative question discusses options for private methods, but this is regarding a public method, and to test it I need to access a private field, so the many statements of "if you need to access private methods/classes, you're doing it wrong" doesn't seem to apply here.

like image 265
NickZ Avatar asked Oct 23 '25 03:10

NickZ


1 Answers

We should write tests that exercise the public API. It's not always possible though. In this case I would write a test that exercises two methods together, push and pop because these two make a functional stack:

public class Stack {
    private StackNode base;

    public void push(Object item) {
        ...
    }

    // I know this wasn't part of your code
    public Object pop() {
        ...
    }
}

public class TestStack {
    @Test
    public void testOnePush() {
        // GIVEN
        Stack st = new Stack();

        // WHEN
        st.push(new Integer(3)); 
        Object popped = st.pop();

        assertEquals(popped, new Integer(3));
    }
}

If this kind of testing is not possible, then it's okay to expose base either directly or through a getter. In this case I prefer to write a warning comment, i.e. it's only for testing:

public class Stack {
    StackNode base; // package-private for testing reasons
}

It's possible to warn the other developers with method names too:

public class Stack {
    private StackNode base;

    /** For unit tests only!!! */
    public StackNode getBaseForTests() {
         return base;
    }
}
like image 121
Tamas Rev Avatar answered Oct 25 '25 22:10

Tamas Rev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!