Why is my stubbed method returning null?

I have a Dummy class. I add 3 variables. However, one of them is not injectable, because it is an interface. Therefore, I add an object, one of the methods of which returns the desired type.

 Class Dummy { private final Class1 class1; private final Class2 class2 private final Interface1 interface1; @Inject Dummy(Class1 class1, Class2 class2, HelperClass helperclass) { this.class1 = class1; this.class2 = class2; this.interface1 = helperclass.somefunction(); } } 

HelperClass somefunction returns an instance of Interface1 .

This is my test:

 @RunWith(MockitoJUnitRunner.class) Class DummyTest { @Mock private Class1 class1; @Mock private Class2 class2; @Mock private HelperClass helperclass; @InjectMocks private Dummy dummy; @Before public void start() { Interface1 mockInterface = mock(Interface1.class); when(helperclass.somefunction()).thenReturn(mockInterface); } @Test public void test() { // etc... } } 

However, when you run the test, Interface1 is null. What am I doing wrong?

+5
source share
1 answer

@InjectMocks occurs before the @Before annotation.

For this reason (and other reasons ), I recommend not using @InjectMocks at all ; just create a SUT class in the @Before method with a real constructor.

This ordering is obvious when you add multiple print statements to your test class. I removed all the Class1 and Class2 tags, as this is not relevant. See this code run:

 @RunWith(MockitoJUnitRunner.class) public class DummyTest { @Mock private HelperClass helperclass; @InjectMocks private Dummy dummy; @Before public void start() { System.out.println("In @Before!"); Interface1 mockInterface = mock(Interface1.class); when(helperclass.somefunction()).thenReturn(mockInterface); } @Test public void test() { System.out.println("In @Test!"); } public static class Dummy { public final Interface1 interface1; public final HelperClass helperclass; @Inject Dummy(HelperClass helperclass) { System.out.println("In dummy constructor!"); this.interface1 = helperclass.somefunction(); this.helperclass = helperclass; } } private static class HelperClass { Interface1 somefunction() { return new Interface1() {}; } } private static interface Interface1 { } } 

Output:

 In dummy constructor! In @Before! In @Test! 

If you insist on doing this with @Mock and @InjectMocks , you can try using answer instead:

 @Mock(answer=Answers.RETURNS_MOCKS) 

will make helperclass.somemethod() return the layout instead of null .


Honestly, it is not surprising that it works that way. Mockito authors really dislike Partial Mocks / Stubs and explicitly talk about this in their documentation :

As usual, you'll read partial layout recognition . Object-oriented programming more or less complicates complexity by dividing complexity into separate specific SRPy objects. How does a partial layout fit into this paradigm? Well, it's just not ... A partial layout usually means that the complexity has been transferred to another method on the same object. In most cases, this is not the way you want to develop your application.

However, there are rare cases where partial layouts come in handy: dealing with code that you cannot easily change (third-party interfaces, temporary refactoring of legacy code, etc.). However, I would not use partial layouts for new, and well-designed code.

If helperclass returns something other than null , it is a partial layout, and therefore they will not like it.

+6
source

All Articles