Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking spring method annotation throws NullPointerException in test cases

I have a custom validation annotation in a spring project.

The aim for annotation is to accept the parameter names that are supposed to be id and dept values.

The aim of the aspect is to fetch the paramNames from the annotation, find the corresponding parameter position in the method signature, get the values from the identified positions and perform validation with the values.

Here are the classes I have written so far.

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface ValidateDeptAnnotation {
    String id();
    String dept();
}

The aspect that does the validation when a method is annotated.

@Aspect
@Component
public class ValidateDeptAspect {

    @Before("@annotation(<package>.ValidateDeptAnnotation)")
    public void runValidation(JoinPoint joinPoint) throws MemberIdentityException {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        ValidateDeptAnnotation annotation = method.getAnnotation(ValidateDeptAnnotation.class); 
        String id = null;
        String dept = null;
        for (int index = 0; index < signature.getParameterNames().length; index++) {
            String paramterName = signature.getParameterNames()[index];
            if (annotation.dept().equals(paramterName)) {
                dept = joinPoint.getArgs()[index].toString();
            } else if (annotation.id().equals(paramterName)) {
                id = joinPoint.getArgs()[index].toString();
            }
        }
        //....further processing...throw appropriate error msgs logic
    }

}

The test class

@RunWith(PowerMockRunner.class)
@PrepareOnlyThisForTest({Method.class})
public class ValidateDeptAspectTestMockedMethod {
    @InjectMocks
    private ValidateDeptAspect validationAspect;
    @Mock
    private JoinPoint joinPoint;

    @Mock
    private MethodSignature methodSignature;
    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }
    @Test
    public void testIdParamNotFound() {
        String[] methodSignatureParams = {"id","dept"};
        String[] argumentValues= {"789","dept-789-pacman"};

        Mockito.doReturn(methodSignature).when(joinPoint).getSignature();
        Mockito.doReturn(methodSignatureParams).when(methodSignature).getParameterNames();
        Mockito.doReturn(argumentValues).when(joinPoint).getArgs();
        ValidateDeptAnnotation annotation = Mockito.mock(ValidateDeptAnnotation.class);

        Method mockedMethod = PowerMockito.mock(Method.class);
        Mockito.doReturn(mockedMethod).when(methodSignature).getMethod();
        PowerMockito.doReturn(annotation).when(mockedMethod).getAnnotation(Mockito.any());
        //        PowerMockito.when(mockedMethod.getAnnotation(ValidateDept.class)).thenReturn(annotation); --didnot work, same error.
        Mockito.doReturn("iiiiid").when(annotation).id();
        Mockito.doReturn("dept").when(annotation).dept();

        validationAspect.runValidation(joinPoint);


        ///...further assertion logic to check for error message as iiiid != id
        //but never gets here.

   }
}

When I run the test case, it fails with NullPointerException at the line in the Aspect.

if (annotation.dept().equals(paramterName))  

When I debug the test case, the annotation is obtained properly here.

PowerMockito.doReturn(annotation).when(mockedMethod).getAnnotation(Mockito.any());

However, the call to the aspect method throws NPE. Any help is much appreciated.

Thanks in advance.

like image 716
Vijay Kalidindi Avatar asked Apr 15 '26 06:04

Vijay Kalidindi


2 Answers

For those who wander into this situation. I haven't figured how to solve the problem or what the problem is.

I have settled for this approach currently - Create dummy methods in the test case that reflect your test case and proceed with test cases normally.

Code:

@RunWith(MockitoJUnitRunner.class)
public class ValidateDeptAspectTestMockedMethod {

    @InjectMocks
    private ValidateDeptAspect validationAspect;
    @Mock
    private JoinPoint joinPoint;

    @Mock
    private MethodSignature methodSignature;
    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }
    @Test
    public void testIdParamNotFound() {
        String[] methodSignatureParams = {"id","dept"};
        String[] argumentValues= {"789","dept-789-pacman"};

        Mockito.doReturn(methodSignature).when(joinPoint).getSignature();
        Mockito.doReturn(methodSignatureParams).when(methodSignature).getParameterNames();
        Mockito.doReturn(argumentValues).when(joinPoint).getArgs();

        Method method = myMethod("noMemberId");
        Mockito.doReturn(method).when(methodSignature).getMethod();

        validationAspect.runValidation(joinPoint);


        ///...further assertion logic to check for error message
        // The test is successful.
    }

    @ValidateDeptAnnotation(memberId = "",accessToken = "accessToken")
    private void noMemberId(String memberId, String accessToken) {}
}
like image 91
Vijay Kalidindi Avatar answered Apr 17 '26 19:04

Vijay Kalidindi


I faced same situation when I try to write an unit test of an aspect. Finally, I find the problem is you can't mock the Method class. You can get your method through reflect:

Method method = TestClass.class.getDeclaredMethod("yourMethod");

And it can help you to get your Annotation. Hope it can help.

like image 37
JiaSong Song Avatar answered Apr 17 '26 19:04

JiaSong Song



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!