java – 如何在我的示例中模拟一个具有静态字段的类?

我试图解决这个问题已经两天了!
事情就是这样:我有一个类如下:


public class TaskEntity extends Index {

    public String title;
    public String description;
    public UUID posterId;
    public Long time;
    public String address;
    public GeoPoint location;

    public static Finder find = new Finder(TaskEntity.class);

    //some methods
}

它扩展了这个抽象类:


public abstract class Index implements Indexable {
    //some public non static fields
    // some methods

    public static class Finder {
        private final Class type;
        private IndexQueryPath queryPath;

        public Finder(Class type) {
            this.type = type;
            T t = IndexUtils.getInstanceIndex(type); // error here!
            this.queryPath = t.getIndexPath();
        }

        public IndexQueryPath getIndexPath() {

            IndexType indexTypeAnnotation = this.getClass().getAnnotation(IndexType.class);
            if(indexTypeAnnotation == null) {
                Logger.error("ElasticSearch : Class " + this.getClass().getCanonicalName() + " no contain @IndexType(name) annotation ");
            }
            String indexType = indexTypeAnnotation.name();

            String indexName = IndexService.INDEX_DEFAULT; // This is not defined, therefore throw a NullPointerException
            IndexName indexNameAnnotation = this.getClass().getAnnotation(IndexName.class);
            if(indexNameAnnotation != null) {
                indexName = indexNameAnnotation.name();
            }

               return new IndexQueryPath(indexName, indexType);
         }

        // some methods
    }

}

我只是尝试模拟TaskEntity类,而不需要任何额外的代码,如下所示:


public class TaskManagementServiceImplTest {
    @Mock
    private TaskEntity taskEntity;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void emptyTest(){

    }
}

繁荣:


java.lang.ExceptionInInitializerError
    at com.github.cleverage.elasticsearch.Index.getIndexPath(Index.java:41)
    at com.github.cleverage.elasticsearch.Index$Finder.(Index.java:164)
    at models.elasticsearch.TaskEntity.(TaskEntity.java:48)
    at sun.reflect.GeneratedSerializationConstructorAccessor6.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:45)
    at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
    at org.mockito.internal.creation.jmock.ClassImposterizer.createProxy(ClassImposterizer.java:128)
    at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:63)
    at org.powermock.api.mockito.internal.mockcreation.MockCreator.createMethodInvocationControl(MockCreator.java:111)
    at org.powermock.api.mockito.internal.mockcreation.MockCreator.mock(MockCreator.java:60)
    at org.powermock.api.mockito.PowerMockito.mock(PowerMockito.java:143)
    at org.powermock.api.extension.listener.AnnotationEnabler.standardInject(AnnotationEnabler.java:84)
    at org.powermock.api.extension.listener.AnnotationEnabler.beforeTestMethod(AnnotationEnabler.java:51)
    at org.powermock.tests.utils.impl.PowerMockTestNotifierImpl.notifyBeforeTestMethod(PowerMockTestNotifierImpl.java:90)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:292)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:86)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:33)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:45)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:118)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:104)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:53)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.NullPointerException
    at com.github.cleverage.elasticsearch.IndexService.(IndexService.java:45)
    ... 36 more


我正在嘲笑我的TaskEntity类,以避免初始化我的搜索引擎.但是,正如我所知,即使我想模仿它,它也试图访问不应该的东西.有办法避免这种情况吗?有没有办法模拟TaskEntity并以某种方式忽略该“查找”字段?
任何帮助表示赞赏!

解决方法:

我认为简单的解决方案是模拟IndexUtils.getInstanceIndex(type)调用.这看起来像是一个静态调用,它设置了t变量,然后尝试在下一行使用t.getIndexPath();.在模拟静态IndexUtils时,请确保在@PrepareForTest注释中至少包含IndexUtils和Finder.这需要在setUp()中处理,但在尝试initMocks(this)之前.这样,当执行到达错误行时(在初始化TaskEntity模拟时),它将有钩子返回正确的模拟值以继续设置.

如果你希望代码根本不进入Finder构造函数,可能需要更多的箍才能跳过.你的设置必须改变一点来处理静态.确保在@PrepareTest注释中仍然包含Finder和TaskEntity.

@Mock
private TaskEntity taskEntity;
@Mock
private Finder findMock;

@Before
public void setUp() throws Exception {
  PowerMockito.mockStatic(Finder.class);
  PowerMockito.whenNew(Finder.class).withArguments(TaskEntity.class).thenReturn(findMock);
  MockitoAnnotations.initMocks(this);
}

@Test
public void emptyTest(){

}

上面的代码有点棘手,我不确定它是否适合你.我无法在本地创建一些shell类来进行测试.我尝试简化你提供的那些,但我仍然试图掌握你拥有的所有复杂对象之间的设置和相关性.如果有任何错误,请告诉我,我可以尝试通过它们进行调试.

上一篇:在测试之间重置Mockito模拟,作为Spring bean提供?


下一篇:使用spring-test-mvc jsonpath进行测试返回null