Nipul Sindwani
Nipul Sindwani

Reputation: 81

how to mock the method call which is not done by some dependency of the class?

I am trying to write JUnits for some class which is as follows

class C{
    public C fun(D d){
       // fetch some data from database using object of D
       // do some operations on that data 
       // create an object of C using this data
       // return that object of C
    }
 }
@Component
class toBeTested{
   @Autowired private A a;
   @Autowired private B b;
   public C methodToBeTested(){
        C c = new C(a.getD()).fun();
        return c;
   } 
}

I want to test methodToBeTested() method. Please tell is there any way In which we can mock the method calls of object D present in class C while execution of fun() method. Or If there is some other easy way to handle this situation in mockito. All I have found until now is this Stack overflow but still I am not clear how to use this in my situation

Upvotes: 1

Views: 904

Answers (2)

Mark Bramnik
Mark Bramnik

Reputation: 42441

If you use @Autowired in class C, this C should be managed by Spring, otherwise the "autowiring magic of D inside C won't happen"

But if so, why do you create a new instance of C in class toBeTested? It doesn't really make sence.

So you should:

  1. Place @Component on class C so that Spring will manage it.
  2. Modify class toBeTested:
@Component
class toBeTested{
   @Autowired private A a;
   @Autowired private B b;
   @Autowired private C c; 
   public C methodToBeTested(){
        return c.fun();
   } 
}

Its quite strange to see c.fun() that returns itself, is it a builder or something? Maybe you should make it 'prototype scope' and then the solution is slightly different, but since its not mentioned in the question, I don't have enough details so I'll leave the answer as is...

Update 1

Now when its clear that class C for reasons which are beyond the control of OPs is not managed by spring, there are two options:

  1. Use PowerMock/Power Mockito if you have to preserve class toBeTested in its current form (with new C() in the method to be tested. This approach in general considered a bad practice use it only if you don't have another choice. These tools can mock the creation of object (new) and substitute C with some stub on the fly.

  2. If you can change the class toBeTested - use dependency injection:

public class ToBeTested {
   @Autowired private A a;
   @Autowired private B b;
   @Autowired private CFactory cFactory; 

   public C methodToBeTested() {
      return cFactory.create(a.getD()).fun();
   }  
}

interface CFactory {
    C create(D d);
}

@Component
public class DefaultCFactoryImpl implements CFactory {
   public C createC(D d) {
      return new C(d);
   }
}

This approach is much better because it allows to substitute the factory with the implementation that will create a mock of C or whatever you'll find appropriate for the test.

Upvotes: 2

dehasi
dehasi

Reputation: 2773

It's always better to use a constructor injection.

But if you don't want to refactor, you can use @InjectMocks from mockito.

class ToBeTestedTest {
   @Mock private A a;
   @Mock private B b;
   @InjectMocks ToBeTested toBeTested; // mockito will inject your mocks

   @Before
   public void setUpMocks() {
      when(a.getSomeParameter()).thenReturn(new DummyObject())
   }
}

Upvotes: 0

Related Questions