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.
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With