Junit PowerMockito和AspectJ给了我NullPointerException

Junit PowerMockito和AspectJ给了我NullPointerException,junit,aspectj,spring-roo,powermock,Junit,Aspectj,Spring Roo,Powermock,我有一个正在测试的类,看起来像这样: import org.springframework.roo.addon.javabean.RooJavaBean; import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord; @RooJavaBean @RooJpaActiveRecord(table="test_class", finders={ "findById" }) public class TestCla

我有一个正在测试的类,看起来像这样:

import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;

@RooJavaBean
@RooJpaActiveRecord(table="test_class", finders={ "findById" })
public class TestClass {
    boolean test;

    public static String returnSomething() {
        return "X";
    }
}
public class LockWithRequestTimeout implements ReadWriteLock
//...
@TracePerformance // ----> this annotation somehow influence PowerMockito
@Override
public void lock()
{
  try
  {
    while (!l.tryLock(1, TimeUnit.SECONDS))
    {
      PerformanceAdvice.checkRequestTimeout(() -> toString()); // ----> this is what i wanted to mock, PerformanceAdvice is AOP that handles TracePerformance annotation
    }
  }
  catch (final InterruptedException e)
  {
    final String msg = "interrupted while waiting for " + this;
    LogFactory.getLog(LockWithRequestTimeout.class).warn(msg);
    Thread.currentThread().interrupt();
    throw new RuntimeException(msg, e);
  }
}
//...
如您所见,它有Roo注释和我需要模拟的静态方法

我的测试使用(模拟的)静态方法,并且还从这个类创建新对象

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(TestClass.class)
@PowerMockIgnore("javax.management.*")
public class PowerMockitoTest {

    @Test
    public void test() {
        PowerMockito.mockStatic(TestClass.class);
        PowerMockito.when(TestClass.returnSomething()).thenReturn("Y");

        Assert.assertEquals("Y", TestClass.returnSomething());

        TestClass x = new TestClass();
    }

}
调用
newtestclass()
会给我以下异常:

java.lang.NullPointerException
    at org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect.ajc$if$bb0(AnnotationBeanConfigurerAspect.aj:1)
    at ....TestClass.<init>(TestClass.java:8)
这是Powermock中的bug吗? 有什么解决办法吗

使用的版本:

[INFO] +- junit:junit:jar:4.11:test
[INFO] |  \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- org.mockito:mockito-all:jar:1.9.5:test
[INFO] +- org.powermock:powermock-module-junit4:jar:1.5.3:test
[INFO] |  \- org.powermock:powermock-module-junit4-common:jar:1.5.3:test
[INFO] |     \- org.powermock:powermock-reflect:jar:1.5.3:test
[INFO] +- org.powermock:powermock-api-mockito:jar:1.5.3:test
[INFO] |  \- org.powermock:powermock-api-support:jar:1.5.3:test
[INFO] +- org.powermock:powermock-module-junit4-rule:jar:1.5.1:test
[INFO] |  +- org.powermock:powermock-classloading-base:jar:1.5.1:test
[INFO] |  \- org.powermock:powermock-core:jar:1.5.1:test
[INFO] \- org.powermock:powermock-classloading-xstream:jar:1.5.1:test

当然,这不是真的,但是:PowerMock是一个bug。一旦你开始使用它,你就必须准备在这些问题上花费大量时间

特别是当你开始混合力量的时候。。。使用另一个执行字节码操作的库。这简直是自找麻烦

因此,从长远来看,你将从中受益的唯一答案是:不要这样做。不要使用PowerMock

相反:要明白,PowerMock启用测试所需的每一种情况(如静态方法调用)都想告诉您:“您的设计不好,去修复它”


如果您确实遇到了不允许设计更改的情况,那么您可能仍然不希望使用PowerMock;最坏的情况是考虑为这个角落写一些真正的“功能”测试,只是为了避免你现在正面临的情况。

< P>我的代码中也有类似的问题。不幸的是,我不得不模拟内部组件的行为,比如:

import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;

@RooJavaBean
@RooJpaActiveRecord(table="test_class", finders={ "findById" })
public class TestClass {
    boolean test;

    public static String returnSomething() {
        return "X";
    }
}
public class LockWithRequestTimeout implements ReadWriteLock
//...
@TracePerformance // ----> this annotation somehow influence PowerMockito
@Override
public void lock()
{
  try
  {
    while (!l.tryLock(1, TimeUnit.SECONDS))
    {
      PerformanceAdvice.checkRequestTimeout(() -> toString()); // ----> this is what i wanted to mock, PerformanceAdvice is AOP that handles TracePerformance annotation
    }
  }
  catch (final InterruptedException e)
  {
    final String msg = "interrupted while waiting for " + this;
    LogFactory.getLog(LockWithRequestTimeout.class).warn(msg);
    Thread.currentThread().interrupt();
    throw new RuntimeException(msg, e);
  }
}
//...
我的第一个想法是模拟PerformanceDevice checkRequestTimeout方法,但它的行为就像在您的示例中,我得到了NullPointerException

我的解决方案是进行小型重构,我提取了新方法:

protected static void checkRequestTimeout(final Supplier<String> msg)
{
  PerformanceAdvice.checkRequestTimeout(msg);
}

然后把它转移到某种类型的UTIL?对于其他未被Roo注释的类,我提交了一个bug并提供了一个修复:

1。您将如何对高于DB调用一层的函数进行单元测试?没有嘲弄。2.在没有模拟的情况下,如何使用JerseyTest进行API测试。。。。就我个人而言,我更喜欢JMockit,但它在支持方面也有问题,因为只有一个作者。3.如果你批评,也要提出改进的方法。事实上,你的帖子非常傲慢。那设计有什么不好?把它写下来,否则不要说它不好。