Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock an interface with two different implementation [duplicate]

I have a class I need to test that has two instance of different class but same interface. This is how the codes looks like,

Class to be tested:

@Service
public class MainClass {
   @Resource(name = "aClass")
   private IClass instance1;
   @Resource(name = "bClass")
   private IClass instance2;
}

Other classes:

@Service("aClass")
public class A implements IClass {}

@Service("bClass")
public class B implements IClass {}

My Unit Test:

public MainClassTest {
   @InjectMocks
   private MainClass mainClass;

   @Mock
   private IClass instance1;
   @Mock
   private IClass instance2;

   @Test
   public void test() {...}
}

When I run the test, both instance1 and instance2 are null since they are not mocked. This doesn't happen when the interface has only one implementation.

Any idea how to handle this?

Thanks, Angelo

like image 221
Demian Avatar asked Sep 18 '17 15:09

Demian


People also ask

Can an interface have multiple implementations?

Java does not support "multiple inheritance" (a class can only inherit from one superclass). However, it can be achieved with interfaces, because the class can implement multiple interfaces. Note: To implement multiple interfaces, separate them with a comma (see example below).

Can you mock an interface?

mock() method allows us to create a mock object of a class or an interface. We can then use the mock to stub return values for its methods and verify if they were called.

Can we use @qualifier with @mock?

@MockBean with @QualifierIf an interface has more than one implementation class then to choose the exact class for dependency injection, @Qualifier annotation is used. Here we will show the demo to use @MockBean with @Qualifier annotation. Find the classes used in our unit test class.

How do you mock another method in the same class which is being tested?

Instead of using mock(class) here we need to use Mockito. spy() to mock the same class we are testing. Then we can mock the method we want as follows. Mockito.


1 Answers

@InjectMocks is a short cut which tells Mockito to instance your MainClass and to try to inject mocks by one of constructor injection or setter injection or property injection (in order, IIRC).

I think the behaviour you are seeing may be known behaviour for Mockito; there's an open issue describe here realting to Mockito's handling of @InjectMocks with two instances of the same mocked type.

So, instead of relying on it, you could create the instance of MainClass the 'old fashioned' way e.g. in a @Before method. For example:

private MainClass mainClass;

@Before
public void setup() {
    IClass instance1 = mock(IClass.class); 
    IClass instance2 = mock(IClass.class);

    mainClass = new MainClass(instance1, instance2);
}
like image 145
glytching Avatar answered Oct 06 '22 00:10

glytching