1

How does this even work? As per my understanding it shouldn't have. LDAPGroupAccessor is being new initialized in class or can be new initialized in constructor itself, it is not being injected, is not a constructor argument, not a spring bean injection.

I know it is possible using reflection, but how is injectMocks injecting it ? Doesn't this defeat the purpose of DI ?

@Component
public class AuthorizationHandler {

    private LDAPGroupAccessor groupAccessor = new LDAPGroupAccessor();

    public isUserAuthorized(String userId, String groupId){
        return groupAccessor.isUserInGroup(userId, ldapGroup);
    }
}

public class AuthorizationHandlerTest {

    @InjectMocks
    private AuthorizationHandler authorizationHandler;

    @Mock
    private LDAPGroupAccessor groupAccessor = new LDAPGroupAccessor();

    @Before
    public void setup() {
        String authorizedUser = "authorizedUser";
        Mockito.when(groupAccessor.isUserInGroup("authorizedUser", "someGroup")).thenReturn(true);
    }

    @Test
    public void test1() {
        Assert.assertEquals(true, authorizationHandler.isUserAuthorized("authorizedUser", "someGroup"));
    }
}
G8XSU
  • 98
  • 1
  • 9

1 Answers1

2

It just uses field injection. From the documentation

Field injection; mocks will first be resolved by type (if a single type match injection will happen regardless of the name), then, if there is several property of the same type, by the match of the field name and the mock name.

So the steps are:

  1. AuthorizationHandler is instantiated
  2. The instance initialiser is called
  3. An LDAPGroupAccessor is created and assigned to groupAccessor
  4. @InjectMocks runs and replaces the instance allocated to groupAccessor with the @Mock
Boris the Spider
  • 59,842
  • 6
  • 106
  • 166
  • I thought mockito would only do field injection in case LDAPGroupAccessor is being field injected that is : `@Autowired private LDAPGroupAccessor groupAccessor;` – G8XSU May 19 '18 at 10:36
  • Mockito has nothing to do with Spring! Where did you get that idea from @G8XSU? `@InjectMocks` isn't a DI framework, it's a utility for making unit testing easier - as such it does not respect or care about DI annotations, epecially not those from specific frameworks - such as Spring. – Boris the Spider May 19 '18 at 10:36
  • Ok, I agree, But i think the ideal way would have been to make LDAPGroupAccessor also a component and then autowire it, inject it in test cases. Is the only advantage here: "it would be clear that AuthorizationHandler expects groupAccessor to be externally injected" and no other benefit ? – G8XSU May 19 '18 at 10:43
  • That's not a decision I can make for you - I have no idea what this code does, you asked for an explanation of the behvaiour and you have it... Generally speaking, however, yes - it is almost always best to take a dependency in the ctor and declare it `private final` (yours isn't `final`); as instatiating things in ctors leads to tightly coupled, untestable code. – Boris the Spider May 19 '18 at 10:45
  • In this particular case, even if it was ctor initialized, injectMocks would have still injected it. I am not sure how it makes it tightly coupled or untestable. – G8XSU May 19 '18 at 10:57
  • That's because it's designed to help test untestable code - that's almost the definition of Mockito... – Boris the Spider May 19 '18 at 10:58