0

我有一些单元测试,其中底层代码使用了 EncryptedSharedPreferences。由于上述代码,我收到了 Robolectric 无法处理和隐藏本机 KeyStore 实现的异常。目前在 Robolectric 的 Github 上有一个未解决的问题,可以在这里找到。但它似乎在 Android >= 11 上没有任何修复。有什么想法,或者你可能遇到过同样的问题?

正在抛出 KeyStoreException

AndroidKeyStore not found
java.security.KeyStoreException: AndroidKeyStore not found
    at java.base/java.security.KeyStore.getInstance(KeyStore.java:878)
    at androidx.security.crypto.MasterKeys.keyExists(MasterKeys.java:135)
    at androidx.security.crypto.MasterKeys.getOrCreate(MasterKeys.java:87)
    at ...auth.EncryptedAuthState.sharedPreferences(EncryptedAuthState.kt:88)
    at ...auth.EncryptedAuthState.readState(EncryptedAuthState.kt:57)
    at ...auth.EncryptedAuthState.getCurrent(EncryptedAuthState.kt:40)
    at ...auth.EncryptedAuthState.updateAfterTokenResponse(EncryptedAuthState.kt:74)
    at ...EncryptedAuthStateTest.updateIdTokenOnTokenResponse(EncryptedAuthStateTest.kt:126)
    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.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:591)
    at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:274)
    at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:88)
    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.security.NoSuchAlgorithmException: AndroidKeyStore KeyStore not available
    at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:159)
    at java.base/java.security.Security.getImpl(Security.java:700)
    at java.base/java.security.KeyStore.getInstance(KeyStore.java:875)

运行测试时,例如

@ExperimentalFoundationApi
@ExperimentalStdlibApi
@RunWith(RobolectricTestRunner::class)
@Config(shadows = [KeyStoreShadow::class])
class EncryptedAuthStateTest {
    @Test
    fun initialAuthState() {
        val state =
            EncryptedAuthState(InstrumentationRegistry.getInstrumentation().targetContext)
                .getCurrent()

        Assert.assertFalse(state.isAuthorized)
        Assert.assertNull(state.accessToken)
        Assert.assertNull(state.accessTokenExpirationTime)
        Assert.assertNull(state.idToken)
        Assert.assertNull(state.refreshToken)
        Assert.assertNull(state.lastAuthorizationResponse)
        Assert.assertNull(state.lastTokenResponse)
        Assert.assertNull(state.lastRegistrationResponse)
        Assert.assertNull(state.scope)
        Assert.assertNull(state.scopeSet)
    }
}

加密身份验证状态

private fun sharedPreferences(): SharedPreferences {
        val masterKey: MasterKey = MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
            .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
            .build()

        return EncryptedSharedPreferences.create(
            context,
            "AuthState",
            masterKey,
            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        )
    }

我试图创建一个影子类,但这没有被触发:

import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;

@Implements(KeyStore.class)
public class KeyStoreShadow {
    @Implementation
    public static KeyStore getInstance(String type)
            throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(new FileInputStream(
                System.getProperty("java.home") + "/lib/security/cacerts"), null);
        return keyStore;
    }
}

资源

4

0 回答 0