Springboot Mockito - problem with mocking

38 Views Asked by At

So I added functionality to allow users to change only their own profile info but I'm having problem with adding that logic to test.

This is my Service and function where I check if user that is sending request is trying to update his own details.

public ApplicantDetailsResponseDTO updateByUserID(Integer id, ApplicantDetailsRequestDTO newApplicantDetails) {
        ApplicantDetails applicantDetails = applicantDetailsRepository.findByUserId(id)
                .orElseThrow(() -> new EntityNotFoundException("Details of applicant with ID " + id + " not found"));

        if(!isAuthorizedForChange(applicantDetails.getUser().getUsername())) {
            return null;
        }

        applicantDetails.setFirstname(newApplicantDetails.getFirstname());
        applicantDetails.setLastname(newApplicantDetails.getLastname());
        applicantDetails.setPhoneNumber(newApplicantDetails.getPhoneNumber());

        ApplicantDetails updatedApplicantDetails = applicantDetailsRepository.save(applicantDetails);
        return applicantDetailsMapper.mapToApplicantDetailsResponseDTO(updatedApplicantDetails);
    }

    public boolean isAuthorizedForChange(String username) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        UserDetails currentUser = (UserDetails) authentication.getPrincipal();

        return Objects.equals(username, currentUser.getUsername());
    }

This is my setup for test

 @InjectMocks
    private ApplicantDetailsService applicantDetailsService;
    @Mock
    private ApplicantDetailsRepository applicantDetailsRepository;
    @Mock
    private ApplicantDetailsMapper applicantDetailsMapper;


    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
    }

And this is my try to mock isAuthorizedForChange and return true

Mockito.when(applicantDetailsService.isAuthorizedForChange("username")).thenReturn(true);

Problem is that function is still trying to run when I get to isAuthorizedForChange and get this error:

java.lang.NullPointerException: Cannot invoke "org.springframework.security.core.Authentication.getPrincipal()" because "authentication" is null

Is there a way just to return true when isAuthorizedForChange is called then I will create 2 test cases for when its true and when its false and test behavior.

4

There are 4 best solutions below

0
Feel free On

I think your SecurityHolder doesn't have any context and auth. So we need to mock data for it.

SecurityContext securityContext = Mockito.mock(SecurityContext.class);
Authentication authentication = new UsernamePasswordAuthenticationToken("username", "password");
        Mockito.when(securityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);
0
HelloWorld On

It worked when I moved isAuthorizedForChange into its own service then mocked it like this:

@Mock
private AuthorizeUser authorizeUser;

I guess it wasn't mocking because it was inside service I was injecting mocks?

0
knittl On

You should be able to simply set the Authentication of the SecurityContext to the value you need in your test:

try {
  SecurityContextHolder.setContext(
      new SecurityContextImpl(
          new TestingAuthenticationToken(
              yourPrincipal,
              yourCredentials)));
  // your test code
} finally {
  SecurityContextHolder.clearContext();
}
0
Sivaram Rasathurai On

To effectively mock a static method in your code using Mockito, follow these steps:

Add the dependency to your pom.xml for Maven projects or build.gradle for Gradle projects:

For Maven

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>5.2.0</version>
    <scope>test</scope>
</dependency>

For Gradle

testImplementation 'org.mockito:mockito-inline:5.2.0'

Utilize the MockedStatic class provided by Mockito to mock the static method. Here's how you can do it:

import org.mockito.Mockito;
import org.mockito.MockedStatic;

// Your test method
try (MockedStatic<SecurityContextHolder> holder = Mockito.mockStatic(SecurityContextHolder.class)) {
    converter.when(SecurityContextHolder::getContext).thenReturn(mock(Context.class));

    // Write your other mocks and your test logic here
}

Replace Context.class with the appropriate class that you expect SecurityContextHolder.getContext() to return in your test scenario.

By following these steps, you can effectively mock static methods in your tests using Mockito.

You can see my answer here https://stackoverflow.com/a/72289685/12894468