如何使用REFLECTION或任何其他API初始化最终类中的私有变量?

时间:2017-04-12 19:02:40

标签: java reflection junit mockito powermock

这可能听起来很尴尬,但我试图在最后一堂课中初始化一个私有变量。我已经多次这样做了,我知道它使用Reflection效果很好,但我从来没有真正用最后一堂课做过。由于我无法实例化类,因此我无法传递任何对象来设置变量,这就是我被卡住的地方。

最后的课程

public final class LoggingHandler implements ILoggingHandler {

private Log generalLog; 

/**
 * @param log The general log.
 */
private void setGeneralLog(Log log) {
    generalLog = log;
}

/**
 * @return The general log.
 */
private Log getGeneralLog() {
    return generalLog;
}

JUnit

@Test
public void testSendDocuments() throws Exception {
    AppContext.setApplicationContext( applicationContext );
    IClientUserDto iClientUserDto = mock( IClientUserDto.class );

    DocusignRESTProvider docusignRestProvider = new DocusignRESTProvider();
    docusignRestProvider.setLoggingHandler( iloggingHandler );
    docusignRestProvider.setDocumentManager( iDocumentManager );
    docusignRestProvider.setConfiguration( iProviderConfiguration );
    docusignRestProvider.setManager( iManager );

    Field field = LoggingHandler.class.getDeclaredField( "generalLog" );
    field.setAccessible( true );
    field.set( new Object(), log );

    when( iTransformer.transformRequest( any( SendDocumentsTransformerArgs.class ) ) ).thenReturn( iTransformerResult );
    docusignRestProvider.sendDocuments( iClientUserDto, iDocumentSet );
}

log是一个模拟对象。

堆栈跟踪:

java.lang.IllegalArgumentException: Can not set org.apache.commons.logging.Log field com.mercuryinsurance.esignature.common.logging.LoggingHandler.generalLog to java.lang.Object
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:55)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75)
at java.lang.reflect.Field.set(Field.java:741)
at test.com.mercuryinsurance.esignature.integration.provider.docusign.rest.TestDocusignRESTProvider.testSendDocuments(TestDocusignRESTProvider.java:167)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
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:84)
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:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:122)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:106)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

有人能让我知道有什么其他方法可以测试这样的情况吗?

由于

1 个答案:

答案 0 :(得分:1)

您滥用final类的概念。最终的类可以实例化,它们不能被继承。 因此,在您的情况下LoggingHandler可以并且应该被实例化,除非它的构造函数是私有的。但是如果它的构造函数是私有的 - 这样一个类实现接口的重点是什么?

您应该为Log字段创建公共setter和getter,实例化一个LoggingHandler实例并在测试中传递一个模拟您Log对象。您可以稍后对该模拟进行任何验证。