PowerMockito 和 AspectJ 给我 NullPointerException
PowerMockito and AspectJ giving me NullPointerException
我有一个 Class 正在测试中,看起来像这样:
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";
}
}
如您所见,它有 Roo-Annotations 和我需要模拟的静态方法。
我的测试使用(模拟的)静态方法并且还从这个 class.
创建新对象
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();
}
}
对 new TestClass()
的调用给出了以下异常:
java.lang.NullPointerException
at org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect.ajc$if$bb0(AnnotationBeanConfigurerAspect.aj:1)
at ....TestClass.<init>(TestClass.java:8)
当我调试到 AnnotationBeanConfigurerAspect
class 时,我可以看到传递给此方法的 Configurable
确实为 null
public static final boolean ajc$if$bb0(Configurable c) {
return c.preConstruction();
}
这是 Powermock 中的错误吗?
有什么解决方法吗?
使用的版本:
[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 是 一个错误。在您开始使用它的那一刻,您就必须做好在此类问题上花费大量时间的准备。
尤其是当您开始将 power mock ... 与另一个执行字节码操作的库混合使用时。那简直是自找麻烦
因此,从长远来看,您唯一受益的答案是 运行:不要这样做。不要使用 PowerMock。
相反:了解需要 PowerMock 启用测试(如静态方法调用)的每一种情况都想告诉您:"your design is bad, go fix it"。
而如果你真的遇到不允许设计更改的情况,那么你可能还是宁愿不使用PowerMock;最坏的情况考虑为那个角落编写一些真实的 "functional" 测试 - 只是为了避免您现在面临的情况。
我的代码中有类似的问题。不幸的是我不得不模拟内部组件的行为,像这样:
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);
}
}
//...
我的第一个想法是模拟 PerformanceAdvice checkRequestTimeout 方法,但它的行为就像在你的示例中一样,我得到了 NullPointerException。
我的解决方案是进行小型重构,我提取了新方法:
protected static void checkRequestTimeout(final Supplier<String> msg)
{
PerformanceAdvice.checkRequestTimeout(msg);
}
我没有模拟 PerformanceAdvice,而是在 class LockWithRequestTimeout 中模拟了这个新方法。
我给你的建议是提取方法
public static String returnSomething() {
return "X";
}
并将其移动到某种实用程序?其他未被 Roo
注释的 class
我提交了一个错误并提供了修复:
https://github.com/jayway/powermock/issues/676
我有一个 Class 正在测试中,看起来像这样:
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";
}
}
如您所见,它有 Roo-Annotations 和我需要模拟的静态方法。
我的测试使用(模拟的)静态方法并且还从这个 class.
创建新对象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();
}
}
对 new TestClass()
的调用给出了以下异常:
java.lang.NullPointerException
at org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect.ajc$if$bb0(AnnotationBeanConfigurerAspect.aj:1)
at ....TestClass.<init>(TestClass.java:8)
当我调试到 AnnotationBeanConfigurerAspect
class 时,我可以看到传递给此方法的 Configurable
确实为 null
public static final boolean ajc$if$bb0(Configurable c) {
return c.preConstruction();
}
这是 Powermock 中的错误吗? 有什么解决方法吗?
使用的版本:
[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 是 一个错误。在您开始使用它的那一刻,您就必须做好在此类问题上花费大量时间的准备。
尤其是当您开始将 power mock ... 与另一个执行字节码操作的库混合使用时。那简直是自找麻烦
因此,从长远来看,您唯一受益的答案是 运行:不要这样做。不要使用 PowerMock。
相反:了解需要 PowerMock 启用测试(如静态方法调用)的每一种情况都想告诉您:"your design is bad, go fix it"。
而如果你真的遇到不允许设计更改的情况,那么你可能还是宁愿不使用PowerMock;最坏的情况考虑为那个角落编写一些真实的 "functional" 测试 - 只是为了避免您现在面临的情况。
我的代码中有类似的问题。不幸的是我不得不模拟内部组件的行为,像这样:
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);
}
}
//...
我的第一个想法是模拟 PerformanceAdvice checkRequestTimeout 方法,但它的行为就像在你的示例中一样,我得到了 NullPointerException。
我的解决方案是进行小型重构,我提取了新方法:
protected static void checkRequestTimeout(final Supplier<String> msg)
{
PerformanceAdvice.checkRequestTimeout(msg);
}
我没有模拟 PerformanceAdvice,而是在 class LockWithRequestTimeout 中模拟了这个新方法。
我给你的建议是提取方法
public static String returnSomething() {
return "X";
}
并将其移动到某种实用程序?其他未被 Roo
注释的 class我提交了一个错误并提供了修复: https://github.com/jayway/powermock/issues/676