【问题标题】:PowerMockito and AspectJ giving me NullPointerExceptionPowerMockito 和 AspectJ 给了我 NullPointerException
【发布时间】:2016-06-08 15:31:22
【问题描述】:

我有一个如下所示的待测类:

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 和我需要模拟的静态方法。

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

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 类时,我可以看到传递给此方法的 Configurable 确实为空

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

【问题讨论】:

    标签: junit aspectj spring-roo powermock


    【解决方案1】:

    当然,这不是真的,但是很好:PowerMock 一个错误。当您开始使用它时,您必须准备好在此类问题上花费大量时间。

    特别是当您开始将 power mock ... 与另一个执行字节码操作的库混合时。那简直是自找麻烦。

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

    相反:了解需要 PowerMock 启用测试的每一种情况(如静态方法调用)都想告诉你:“你的设计很糟糕,去修复它”。

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

    【讨论】:

    • 1.您将如何对高于 DB 调用的函数进行单元测试?没有嘲笑。 2. 如何在没有 mocks 的情况下使用 JerseyTest 进行 API 测试? .... 就我个人而言,我更喜欢 JMockit,但由于一个作者,它在支持方面有自己的问题。 3.如果你批评,也提出改进的方式。照原样,你的帖子非常傲慢。那个设计有什么不好的?写下来或者不要说它不好。
    【解决方案2】:

    我的代码中有类似的问题。不幸的是,我不得不模拟内部组件的行为,如下所示:

    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,而是在 LockWithRequestTimeout 类中模拟了这个新方法。

    我对你的建议是提取方法

    public static String returnSomething() {
      return "X";
    }
    

    并将其移动到某种 Utils 中?到其他没有被 Roo 注释的类

    【讨论】:

      【解决方案3】:

      我提交了一个错误并提供了修复: https://github.com/jayway/powermock/issues/676

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-14
        • 2013-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多