模拟spring方法注释在测试用例中抛出NullPointerException

时间:2016-07-12 05:42:25

标签: java mockito junit4 spring-aop powermockito

我在spring项目中有自定义验证注释。

注释的目的是接受应该是id和dept值的参数名称。

该方面的目的是从注释中获取paramNames,在方法签名中找到相应的参数位置,从识别的位置获取值并使用值执行验证。

这是我到目前为止所写的课程。

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

在注释方法时执行验证的方面。

@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
    }

}

测试类

@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.

   }
}

当我运行测试用例时,它在Aspect中的行处失败并显示NullPointerException。

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

当我调试测试用例时,此处正确获取注释。

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

但是,对aspect方法的调用会引发NPE。 任何帮助深表感谢。

提前致谢。

3 个答案:

答案 0 :(得分:1)

对于那些徘徊在这种情况下的人。我还没有想出如何解决问题或问题是什么。

我目前已采用这种方法 - 在测试用例中创建反映测试用例的虚拟方法,并正常进行测试用例。

代码:

@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) {}
}

答案 1 :(得分:0)

我目前处于类似的情况,但我相信测试方面包括连接点触发器。我创建了假类并验证了行为&amp;触发我的方面。它使测试更加全面,并验证了连接点的正确性。

以下代码的2条评论:

  • 我使用spring,主要是因为我总是在Spring中使用AOP,但从概念上讲它可以不用。
  • 代理和AOP并不是齐头并进的。因此,间谍和模拟建议谨慎。

Ť

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestConfig.class})
public class ValidateDeptAspectTestMockedMethod {

    @Autowired
    private SampleService sampleService;



    @Test
    public void testAllWell() {
        sampleService.noMemberId("123", "heroquest");
        // validation etc..
    }

    @Test
    public void testNopeDidntWork() {
        sampleService.noMemberId("123", "heroquest");
        // validation etc..
    }


    @EnableAspectJAutoProxy
    public static class TestConfig {

        @Bean
        public SampleService sampleService() {
            // WARNING - SPYING CAN NO LONGER TRIGGER ASPECT BECAUSE OF PROXY
            return new SampleService();
        }

    }


    public static class SampleService {

        @ValidateDeptAspect(id="789", dept ="dept-789-pacman") 
        public void noMemberId(String id, String dept) {
            // maybe some state you want to save to check after

        }
    }
}

答案 2 :(得分:0)

当我尝试编写方面的单元测试时,我遇到了同样的情况。 最后,我发现问题是您无法模拟Method类。 您可以通过反射获得方法:

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

它可以帮助您获取注释。 希望能有所帮助。