2

Here is the class I want to test

@Component
public class PermissionCheck {

    @Autowired
    private MyEntityRepository myEntityRepository;

    public boolean hasPermission(int myEntityID) {
        MyEntity myEntity = myEntityRepository.findById(myEntityId);
        return myEntity != null;
    }
}

Here is the test class

@RunWith(SpringRunner.class)
public class PermissionCheckTests {

    @MockBean
    private MyEntityRepository myEntityRepository;

    private PermissionCheck permissionCheck;

    @Before
    public void before() {
        this.permissionCheck = new PermissionCheck();
    }

    @Test
    public void shouldHasPermission() {
        MyEntity myEntity = new MyEntity();

        when(this.myEntityRepository.findById(any())).thenReturn(myEntity);
        assertTrue(this.permissionCheck.hasPermission(0));
    }
}

And when I run this test I got

java.lang.NullPointerException
    at PermissionCheck.hasPermission(PermissionCheck.java:line1)
    at PermissionCheckTests.shouldHasPermission(PermissionCheckTests.java:line2)

In the above, line1 and line2 refer to these two lines

        MyEntity myEntity = myEntityRepository.findById(myEntityId);
        assertTrue(this.permissionCheck.hasPermission(0));

And using debugger I see that when entering PermissionCheck.hasPermission from PermissionCheckTests.shouldHasPermission, the repository field

    @Autowired
    private MyEntityRepository myEntityRepository;

is null.

I created these classes by referring to others existing codes, from different places, and without really understanding how to the annotations (partially due to running out of time), so if someone can tell me not only how to fix, but also why I'm wrong, I would really appreciate it!

Edit:

I made the change suggested by @Nikolas Charalambidis (thank you!), so my PermissionCheck class now looks exactly like

@RunWith(SpringRunner.class)
public class PermissionCheckTests {

    @Autowired                                     // you need to autowire
    private PermissionCheck permissionCheck;       // and it uses @MockBean dependency

    @MockBean                                      // if no such @MockBean exists
    private MyEntityRepository myEntityRepository; // the real implementation is used

    @Test
    public void shouldHasPermission() {
        MyEntity myEntity = new MyEntity();

        when(this.myEntityRepository.findById(any())).thenReturn(myEntity);
        assertTrue(this.permissionCheck.hasPermission(0));
    }
}

But I then got the following exception

org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'PermissionCheckTests': 
Unsatisfied dependency expressed through field 'permissionCheck'; 
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type 'PermissionCheck' available: 
expected at least 1 bean which qualifies as autowire candidate. 
Dependency annotations: 
{@org.springframework.beans.factory.annotation.Autowired(required=true), 
@org.springframework.beans.factory.annotation.Qualifier(value="")}

With a little bit search, from this SO answer, I feel like I should not @Autowired PermissionCheck, since it is a class, not an interface.

Does that mean I have to create an interface, @Autowired it and let PermissionCheck implement it? It seems redundant to me, since I don't see why I need such an interface. Is there a way to make it work without creating a new interface which I will solely use for this purpose?

Lansorian
  • 149
  • 3
  • 11

2 Answers2

1

The instance of class PermissionCheck is not properly injected. The tests use the Spring container in the same way as the production code. The following line would not inject the myEntityRepository.

this.permissionCheck = new PermissionCheck();

Spring: NullPointerException occurs when including a bean partly answers your question. You need to @Autowire the thing.

The Spring test context is no different. As long as @MockBean MyEntityRepository exists as a mocked bean, the PermissionCheck will be autowired in the standard way using the mocked class in precedence over the existing bean in the test scope.

@RunWith(SpringRunner.class)
public class PermissionCheckTests {

    @Autowired                                     // you need to autowire
    private PermissionCheck permissionCheck;       // and it uses @MockBean dependency

    @MockBean                                      // if no such @MockBean exists
    private MyEntityRepository myEntityRepository; // the real implementation is used

    @Test
    public void shouldHasPermission() {
        MyEntity myEntity = new MyEntity();

        when(this.myEntityRepository.findById(any())).thenReturn(myEntity);
        assertTrue(this.permissionCheck.hasPermission(0));
    }
}

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • Thank you for your suggestion! But I still having errors... Could you please have a look on the updated part of the question? – Lansorian Feb 16 '21 at 11:39
  • I also ask [a new question](https://stackoverflow.com/questions/66223823/why-autowired-raises-unsatisfieddependencyexception-even-the-class-does-not-im) for that – Lansorian Feb 16 '21 at 11:52
0

in my case i was using lombok i was added @NoArgsConstructor to the class that that i had injected my repository.

@Component
@AllArgsConstructor
@NoArgsConstructor // what cuased the null pointer
public class ParcelUtil {

    private final Logger log = LoggerFactory.getLogger(OrderEventConsumer.class);

    private ParcelRepository parcelRepository;

}

my test:

 @SpringBootTest
    @DirtiesContext
    public class OrderEventConsumerTest extends SpringBootEmbeddedKafka {
        @MockBean
        private ParcelRepository parcelRepository;
    
    }

   

    @Test
        public void update_parcel_inride_to_delivered_nxb() throws JsonProcessingException {
    
            //given
            List<Parcel> parcels = DataUtil.createParcel_inride_and_draft_nxb();
                Mockito
.when(parcelRepository.findFirstByParcelGroupId("12"))
.thenReturn(Optional.ofNullable(parcels.get(0))); //where i got null pointer
 

   
    
    }

}
saba
  • 332
  • 2
  • 14