Suppose I have interface and implementation class that implements it and I want to write unit-test for this. What should I test interface or Impl?
Here is an example:
public interface HelloInterface {
public void sayHello();
}
public class HelloInterfaceImpl implements HelloInterface {
private PrintStream target = System.out;
@Override
public void sayHello() {
target.print("Hello World");
}
public void setTarget(PrintStream target){
this.target = target;
}
}
So, I have HelloInterface and HelloInterfaceImpl that implements it. What is unit-under-test interface or Impl?
I think it should be HelloInterface. Consider following sketch of JUnit test:
public class HelloInterfaceTest {
private HelloInterface hi;
@Before
public void setUp() {
hi = new HelloInterfaceImpl();
}
@Test
public void testDefaultBehaviourEndsNormally() {
hi.sayHello();
// no NullPointerException here
}
@Test
public void testCheckHelloWorld() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream target = new PrintStream(out);
PrivilegedAccessor.setValue(hi, "target", target);
//You can use ReflectionTestUtils in place of PrivilegedAccessor
//really it is DI
//((HelloInterfaceImpl)hi).setTarget(target);
hi.sayHello();
String result = out.toString();
assertEquals("Hello World", result);
}
}
The main line is actually one that I commented out.
((HelloInterfaceImpl)hi).setTarget(target);
Method setTarget()
is not part of my public interface, so I don't want to accidentally call it. If I really want to call it, I should take a moment and think about it. It helps me, for example, to discover that what I'm really trying to do is dependency injection. It opens for me the whole world of new opportunities. I can use some existing dependency injection mechanism (Spring's, for example), I can simulate it myself as I actually did in my code or to take totally different approach. Take a closer look, preparation of PrintSream wasn't that easy, maybe I should use mock object instead?
EDIT:
I think I should always focus on the interface. From my point of view setTarget()
is not part of the "contract" of the impl class neither, it serves sally for dependency injection. I think any public method of Impl class should be considered as private from the testing perspective. It doesn't mean that I ignore the implementation details, though.
See also Should Private/Protected methods be under unit test?
EDIT-2 In the case of multiple implementations\multiple interfaces, I would test all of the implementations, but when I declare a variable in my setUp()
method I would definitely use interface.