Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to inject mocked object into another already mocked object

I have a class that I mocked like this:

@Mock
private MyClass1 mockMyClass1;

Say this class looks like that:

public class MyClass1 {
  @Autowired
  private MyInnerClass myInnerClass;
}

When I mock MyClass1, MyInnerClass will be initialized as null. Is it possible to initialize that private field with another mock objected? I want myInnerClass to be a mock like this one:

@Mock
private MyInnerClass myInnerClass;

If I use the following code:

@InjectMocks
private MyClass1 mockMyClass1;
@Mock
private MyInnerClass myInnerClass

This will initialize the private MyInnerClass inside MyClass1 to be the mocked object, however this way mockMyClass1 is not a mock itself any more, isn't it (I'm only injecting a mocked object inside a real class, just like @Autowired will inject a real object insite it)? Could you correct my logic if I'm wrong in my understanding of @InjectMock and @Mock? Also how could I inject a mocked object inside another mocked object (without using setters/constructors)?

like image 644
Anton Belev Avatar asked Dec 24 '22 10:12

Anton Belev


1 Answers

You are misunderstanding what a mock is.

When you are mocking MyClass1, the inner field of type MyInnerClass doesn't exist anymore for the mocked object. As such, it doesn't make sense to try to inject something into a mock.

A mock is controlled by saying what it should do when you interact with it. You stub its public methods to do what you want them to do. You give behaviour. The only default behaviour (maybe specific to Mockito) is to return null if you didn't configure the mock (but do note that it doesn't return null because some internal variable is null, it returns that because Mockito decided that that's what it should return; maybe another mocking framework decided that it should throw an exception instead, who knows?).

As an example, consider that your real class is:

class MyClass1 {
    private MyInnerClass myInnerClass;
    public MyInnerClass getMyInnerClass() {
        return myInnerClass;
    }
}

Now consider mock a mock of that class. If you call mock.getMyInnerClass(), it is not the real method that is going to be called. What it will return is not the value of myInnerClass. It will return null, or if you have stubbed that method with

when(mock.getMyInnerClass()).thenReturn(something);

then it will return something.

So to answer your question: you can't do that because that's not how mocks work.

like image 165
Tunaki Avatar answered Jan 13 '23 14:01

Tunaki