Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write junit tests for interfaces?

What is the best way to write junit tests for interfaces so they can be used for the concrete implementing classes?

e.g. You have this interface and implementing classes:

public interface MyInterface {     /** Return the given value. */     public boolean myMethod(boolean retVal); }  public class MyClass1 implements MyInterface {     public boolean myMethod(boolean retVal) {         return retVal;     } }  public class MyClass2 implements MyInterface {     public boolean myMethod(boolean retVal) {         return retVal;     } } 

How would you write a test against the interface so you can use it for the class?

Possibility 1:

public abstract class MyInterfaceTest {     public abstract MyInterface createInstance();      @Test     public final void testMyMethod_True() {         MyInterface instance = createInstance();         assertTrue(instance.myMethod(true));     }      @Test     public final void testMyMethod_False() {         MyInterface instance = createInstance();         assertFalse(instance.myMethod(false));     } }  public class MyClass1Test extends MyInterfaceTest {     public MyInterface createInstance() {         return new MyClass1();     } }  public class MyClass2Test extends MyInterfaceTest {     public MyInterface createInstance() {         return new MyClass2();     } } 

Pro:

  • Need only one method to be implemented

Con:

  • Dependencies and mock objects of class under test have to be the same for all tests

Possibility 2:

public abstract class MyInterfaceTest     public void testMyMethod_True(MyInterface instance) {         assertTrue(instance.myMethod(true));     }      public void testMyMethod_False(MyInterface instance) {         assertFalse(instance.myMethod(false));     } }  public class MyClass1Test extends MyInterfaceTest {     @Test     public void testMyMethod_True() {         MyClass1 instance = new MyClass1();         super.testMyMethod_True(instance);     }      @Test     public void testMyMethod_False() {         MyClass1 instance = new MyClass1();         super.testMyMethod_False(instance);     } }  public class MyClass2Test extends MyInterfaceTest {     @Test     public void testMyMethod_True() {         MyClass1 instance = new MyClass2();         super.testMyMethod_True(instance);     }      @Test     public void testMyMethod_False() {         MyClass1 instance = new MyClass2();         super.testMyMethod_False(instance);     } } 

Pro:

  • fine granualtion for each test including dependencies and mock objects

Con:

  • Each implementing test class requires to write additional test methods

Which possibility would you prefer or what other way do you use?

like image 410
Xeno Lupus Avatar asked Jul 17 '11 14:07

Xeno Lupus


People also ask

Can we write JUnit test case for interface?

You can generate a new JUnit test case for an interface that declares annotated methods, or you can update an existing JUnit test case for such an interface.

Do we write test cases for interface?

You can use an abstract test case to test an interface with common tests independent of implementation, and then generate concrete instances of the test case for each implementation of the interface.

Can you unit test interfaces?

To test an interface with common tests regardless of implementation, you can use an abstract test case, and then create concrete instances of the test case for each implementation of the interface.


2 Answers

Contrary to the much-voted-up answer that @dlev gave, it can sometimes be very useful/needful to write a test like you're suggesting. The public API of a class, as expressed through its interface, is the most important thing to test. That being said, I would use neither of the approaches you mentioned, but a Parameterized test instead, where the parameters are the implementations to be tested:

@RunWith(Parameterized.class) public class InterfaceTesting {     public MyInterface myInterface;      public InterfaceTesting(MyInterface myInterface) {         this.myInterface = myInterface;     }      @Test     public final void testMyMethod_True() {         assertTrue(myInterface.myMethod(true));     }      @Test     public final void testMyMethod_False() {         assertFalse(myInterface.myMethod(false));     }      @Parameterized.Parameters     public static Collection<Object[]> instancesToTest() {         return Arrays.asList(                     new Object[]{new MyClass1()},                     new Object[]{new MyClass2()}         );     } } 
like image 89
Ryan Stewart Avatar answered Oct 11 '22 11:10

Ryan Stewart


I strongly disagree with @dlev. Very often it is a very good practice writing tests that use interfaces. Interface defines contract between client and the implementation. Very often all your implementations must pass exactly the same tests. Obviously each implementation can have its own tests.

So, I know 2 solutions.

  1. Implement abstract test case with various tests that use interface. Declare abstract protected method that returns concrete instance. Now inherit this abstract class as many times as you need for each implementation of your interface and implement the mentioned factory method accordingly. You can add more specific tests here as well.

  2. Use test suites.

like image 31
AlexR Avatar answered Oct 11 '22 11:10

AlexR