Access rights to fields related to JUnit tests
Suppose I have a class that implements a linked list style stack:
public class Stack {
private StackNode base;
public void push(Object item) {
if (base == null) {base = new StackNode(item);}
// remaining implementation not shown
}
}
and for it the JUnit testing class:
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 to solve the test class class access problem for base
?
I know about this question , which discusses the issue of access creation, and I know that I might as well put the code Stack
and TestStack
in the package and make the field package base
- private.
I'm wondering what is the best course of action. I know that I shouldn't use pop
in a push
unit test, and vice versa, since this ties these unit tests together.
I think creating a (public) accessory is bad practice unless I want the client code to access the field , so is this the correct call to make an accessory for the field (or the field itself) -private?
Another informative question discusses options for private methods, but this is for a public method and in order to validate it I need to access a private field, so many statements "if you need to access private methods / classes, you are doing it wrong" doesn't seem to apply here.
source to share
We have to write tests that implement the public API. However, this is not always possible. In this case, I would write a test that combines two methods: push
and pop
, because these two create 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 type of testing is not possible, then you can open it base
directly or through a getter. In this case, I prefer to write a warning comment, i.e. For testing only:
public class Stack {
StackNode base; // package-private for testing reasons
}
You can also warn other developers with method names:
public class Stack {
private StackNode base;
/** For unit tests only!!! */
public StackNode getBaseForTests() {
return base;
}
}
source to share
It seems like you've read a lot of questions but haven't gotten to the heart of the message.
The main point: you are not testing internals of your production code. Are you interested in checking the public contract for that. You want to avoid this by checking how to do it.
In other words: if you have a class that implements a stack, then an ideal unit test for such a class ... just tests the behavior of an object of that class. Meaning: You acknowledge that clicking and pop-up values ββproduce the expected results. This occurrence of an empty stack throws an exception ... etc.
If you really want to test, as part, one solution that works without changing the access modifiers is to use Mockito and its @InjectMock annotation.
In other words: you can mock an object StackNode
and @InjectMock does some reflection magic to give you an object Stack
using that mocked StackNode
. Now you can use the Mockito () validation method to make sure this one StackNode
sees the calls you expect to see.
But of course, this means that you are investing a lot of time and energy to write a test that depends entirely on the implementation details Stack
. Once you decide to change it, the whole unit test will break; and you will have to rewrite it completely as well.
And that's why you prefer to check what, not how.
Other than this: it is a common practice that your class and its test class are tested in the same package (not in the same project). And having a packet-protected getter for the field that says // unit test only
is an informal but surprisingly well-working solution.
source to share