【问题标题】:Mocking KeyStore for testing KeyStoreException模拟 KeyStore 以测试 KeyStoreException
【发布时间】:2015-02-12 10:04:14
【问题描述】:

我试图通过模拟 KeyStore 和 KeyStore.getInstance(KEYSTORE_TYPE) 来覆盖 KeyStoreException 块。但是当我嘲笑 KeyStore 时,我得到了 NoSuchAlgorithmException。你能帮我介绍一下异常块吗?

我已经通过How to cover block catch by JUnit with NoSuchAlgorithmException and KeyStoreException,这对覆盖KeyStoreException没有帮助

有什么想法/解决方案吗?

我的代码

package test;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyClass {

    private static final Logger LOG = LoggerFactory.getLogger(MyClass.class);

    private static final String KEYSTORE_TYPE = "PKCS12";
    private static final String SSL_PROTOCOL = "TLS";

    private SSLSocketFactory sslSocketFactory;

    /**
     * getSSLSocketFactory - populates SSLSocketFactory (if empty in this
     * instance) and returns the same.
     * 
     * @return SSLSocketFactory
     * @throws IOException
     *             IOException
     */
    public SSLSocketFactory getSSLSocketFactory() throws IOException {
        if (this.sslSocketFactory == null) {
            InputStream certificateInputStream = null;
            try {
                ClassLoader classLoader = MyClass.class.getClassLoader();
                if (classLoader != null) {
                    String certificateFilePath = "certificateFilePath";

                    certificateInputStream = classLoader.getResourceAsStream(certificateFilePath);

                    String ksPwd = "ksPwd";
                    KeyStore clientStore = KeyStore.getInstance(KEYSTORE_TYPE);
                    clientStore.load(certificateInputStream, ksPwd.toCharArray());

                    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
                    kmf.init(clientStore, ksPwd.toCharArray());
                    KeyManager[] kms = kmf.getKeyManagers();

                    SSLContext sslContext = SSLContext.getInstance(SSL_PROTOCOL);
                    sslContext.init(kms, null, new SecureRandom());
                    this.sslSocketFactory = sslContext.getSocketFactory();
                } 
            } catch (CertificateException ce) {
                LOG.error("Exception while loading secure certificate.", ce);
                // some code
            } catch (NoSuchAlgorithmException nsae) {
                LOG.error("Exception while loading secure certificate.", nsae);
                // some code
            } catch (UnrecoverableKeyException uke) {
                LOG.error("Exception while loading secure certificate.", uke);
                // some code
            } catch (KeyStoreException kse) {
                LOG.error("Exception while loading secure certificate.", kse);
                // some code
            } catch (KeyManagementException kme) {
                LOG.error("Exception while loading secure certificate.", kme);
                // some code
            } finally {
                IOUtils.closeQuietly(certificateInputStream);
            }
        }
        return this.sslSocketFactory;
    }

}

我的测试代码

package test;

import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest({KeyStore.class })
public class MyClassTest {

    @Test
    public void testGetSSLSocketFactory() throws IOException, KeyStoreException {
        KeyStoreException keyStoreException = new KeyStoreException("Test KeyStoreException");
        PowerMockito.mockStatic(KeyStore.class);
        PowerMockito.when(KeyStore.getInstance("PKCS12")).thenThrow(keyStoreException);

        MyClass myClass = new MyClass();
        myClass.getSSLSocketFactory();
        //code to verify mocks
    }

}

堆栈跟踪

11:50:46.270 [main] ERROR test.MyClass - Exception while loading secure certificate.
java.security.NoSuchAlgorithmException: class configured for KeyManagerFactory: com.sun.net.ssl.internal.ssl.KeyManagerFactoryImpl$SunX509 not a KeyManagerFactory
    at sun.security.jca.GetInstance.checkSuperClass(GetInstance.java:242) ~[na:1.6.0_30]
    at sun.security.jca.GetInstance.getInstance(GetInstance.java:221) ~[na:1.6.0_30]
    at sun.security.jca.GetInstance.getInstance(GetInstance.java:147) ~[na:1.6.0_30]
    at javax.net.ssl.KeyManagerFactory.getInstance(KeyManagerFactory.java:121) ~[na:1.6]
    at test.MyClass.getSSLSocketFactory(MyClass.java:55) ~[na:na]
    at test.MyClassTest.testGetSSLSocketFactory(MyClassTest.java:43) [na:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_30]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_30]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_30]
    at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_30]
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68) [junit-4.11.jar:na]
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310) [na:na]
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:88) [junit-4.11.jar:na]
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:96) [junit-4.11.jar:na]
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294) [na:na]
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127) [na:na]
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82) [na:na]
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282) [na:na]
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:86) [junit-4.11.jar:na]
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49) [junit-4.11.jar:na]
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207) [na:na]
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146) [na:na]
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120) [na:na]
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:33) [junit-4.11.jar:na]
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:45) [junit-4.11.jar:na]
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:118) [na:na]
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:101) [powermock-module-junit4-common-1.5.1.jar:na]
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53) [powermock-module-junit4-common-1.5.1.jar:na]
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:53) [powermock-module-junit4-1.5.1.jar:na]
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) [.cp/:na]

【问题讨论】:

    标签: java unit-testing junit mockito powermock


    【解决方案1】:

    KeyStore (java.security.KeyStore) 是一个系统类。因此,请使用“Mocking system classes”中指定的模拟系统类的方法。

    所以你的测试代码如下...

    @RunWith(PowerMockRunner.class)
    @PrepareForTest(MyClass.class)
    public class MyClassTest {
    
        @Test
        public void testGetSSLSocketFactory() throws IOException, KeyStoreException {
            KeyStoreException keyStoreException = new KeyStoreException("Test KeyStoreException");
            PowerMockito.mockStatic(KeyStore.class);
            PowerMockito.when(KeyStore.getInstance("PKCS12")).thenThrow(keyStoreException);
    
            MyClass myClass = new MyClass();
            myClass.getSSLSocketFactory();
            //code to verify mocks
        }
    
    }
    

    注意“@PrepareForTest(.class)”中使用“MyClass”(使用系统类的类)而不是“KeyStore”(需要mock的系统类)。

    【讨论】:

      猜你喜欢
      • 2020-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-19
      • 1970-01-01
      相关资源
      最近更新 更多