首页 > 解决方案 > 意外异常 org.powermock.reflect.exceptions.ConstructorNotFoundException:无法使用参数类型查找构造函数

问题描述

我使用 Android KeyStore 来存储我的应用程序的一些密钥。我创建了一个 KeyProvider 类来获取我的密钥。我有类似的东西:

public class KeyProvider {
 
    public String getKey(String name) {
      KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
      keyStore.load(null);
      KeyStore.Entry entry = keyStore.getEntry(name, null);
      if (entry == null) { // if key is not created, generate key, store it and return
        String myKey = "some_key"
        KeyStore.SecretKeyEntry secretKeyEntry =
            new KeyStore.SecretKeyEntry(
                new SecretKeySpec(myKey.getBytes(), KeyProperties.KEY_ALGORITHM_AES));
        keyStore.setEntry(name, secretKeyEntry, null);
        return myKey;
      } else { // else, return it directly
         KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) entry;
         return String.valueOf(secretKeyEntry.getSecretKey().getEncoded());
      }
    }
}

不,我正在尝试测试 key 不存在的第一个分支。

@RunWith(PowerMockRunner.class)
@PrepareForTest({KeyProvider.class})
public class KeyProviderTest {

  private static final String KEY_STORE_NAME = "AndroidKeyStore";
  private static final String ENCRYPTOR_NAME = "otp";

  @Mock public KeyStore mKeyStore;
  @Mock public KeyStore.SecretKeyEntry mSecretKeyEntry;

  @Before
  public void setUp() {
    PowerMockito.mockStatic(KeyStore.class);
  }

  @Test
  public void testNoExistingKeys() throws Exception {
    PowerMockito.when(KeyStore.getInstance(KEY_STORE_NAME)).thenReturn(mKeyStore);
    when(mKeyStore.getEntry(ENCRYPTOR_NAME, null)).thenReturn(null);
    PowerMockito.whenNew(KeyStore.SecretKeyEntry.class)
        .withAnyArguments()
        .thenReturn(mSecretKeyEntry);
    
    assertThat(KeyProvider.getKeys(ENCRYPTOR_NAME)).isNotNull();
 }
}

但是,我的测试总是失败,原因如下:

[2021-09-06 19:12:50.641][error][tid:22][KeyProvider] Unexpected exception
org.powermock.reflect.exceptions.ConstructorNotFoundException: Failed to lookup constructor with parameter types [ javax.crypto.SecretKey ] in class java.security.KeyStore$SecretKeyEntry.
    at org.powermock.reflect.internal.WhiteboxImpl.getConstructor(WhiteboxImpl.java:287)
    at org.powermock.api.mockito.internal.invocation.MockitoNewInvocationControl.invoke(MockitoNewInvocationControl.java:41)
    at org.powermock.core.MockGateway.newInstanceCall(MockGateway.java:83)
    at com.encryptor.otp.KeyProvider.getKeys(KeyProvider.java:45)
    at com.encryptor.otp.KeyProviderTest.testNoExistingKeys(KeyProviderTest.java:97)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:326)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:310)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access$100(PowerMockJUnit47RunnerDelegateImpl.java:59)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107)
    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:298)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:218)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:160)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:134)
    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:136)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:117)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:57)
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
    at com.testrunner.DelegateRunnerWithTimeout.lambda$runWithBuckManagedTimeout$0(DelegateRunnerWithTimeout.java:116)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.NoSuchMethodException: java.security.KeyStore$SecretKeyEntry.<init>(javax.crypto.SecretKey)
    at java.base/java.lang.Class.getConstructor0(Class.java:3349)
    at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2553)
    at org.powermock.reflect.internal.WhiteboxImpl.getConstructor(WhiteboxImpl.java:279)
    ... 36 more

我不明白为什么 whenNew 的电源模拟不起作用。任何帮助,将不胜感激!

标签: javaandroidjunit

解决方案


推荐阅读