模拟KeyStore以测试KeyStoreException

时间:2014-12-08 06:26:08

标签: java unit-testing junit mockito powermock

我试图通过模拟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]

1 个答案:

答案 0 :(得分:2)

KeyStore(java.security.KeyStore)是一个System类。因此,使用“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”(需要模拟的系统类)。