我有下面的方法,我需要写单元测试。但我不能间谍类KeyStore。它抛出下面的异常。
org.mockito.exceptions.base.MockitoException: Unable to create mock instance of type 'KeyStore'
我可以模拟它。但是当我为模拟方法赋值行为时,它会抛出异常。我调用的方法和得到的异常如下所示。
when(keyStoreMock.getCertificate(anyString())).thenReturn(certificateMock);
java.security.KeyStoreException: Uninitialized keystore
doNothing().when(keyStoreMock).load(any(InputStream.class),Mockito.any(char[].class));
java.lang.NullPointerException
下面是我尝试测试的方法。
public boolean verifySignature(String filePath, String extractContentsPath, String csvParams)
throws ServiceSDKException {
boolean result = false;
String typeOfCertificateStore = "";
String certificateStoreProvider = "";
String certificateName = "";
SignerInformationVerifier verifier = null;
if (filePath != null && extractContentsPath != null && csvParams != null && !filePath.isEmpty()
&& !extractContentsPath.isEmpty() && !csvParams.isEmpty()) {
try {
String[] receivedParams = csvParams.split(",");
typeOfCertificateStore = receivedParams[0];
certificateStoreProvider = receivedParams[1];
certificateName = receivedParams[2];
} catch (ArrayIndexOutOfBoundsException e) {
throw new ServiceSDKException("csvParams should have type of certificate store, certificate store provider and certificate name respectively", e);
}
try {
Path signedDataFilePath = Paths.get(filePath);
Path pathToExtractContents = Paths.get(extractContentsPath);
KeyStore msCertStore = KeyStore.getInstance(typeOfCertificateStore, certificateStoreProvider);
msCertStore.load(null, null);
try {
verifier = new JcaSimpleSignerInfoVerifierBuilder()
.setProvider(certificateStoreProvider)
.build(((X509Certificate) msCertStore.getCertificate(certificateName)));
} catch (Exception e) {
throw new ServiceSDKException("Exception occurred when building certificate",e);
}
verify(signedDataFilePath, pathToExtractContents, verifier);
result = true;
} catch (KeyStoreException | NoSuchProviderException | IOException | NoSuchAlgorithmException
| CertificateException e) {
result = false;
throw new ServiceSDKException("Exception occurred while preparing to verify signature " , e);
}
} else {
throw new ServiceSDKException("FilePath,extract contents path or csv params cannot be empty or null");
}
return result;
}
如何模拟KeyStore及其方法行为?请提供建议。
使用Mockito的新测试方法:
@PrepareForTest(KeyStore.class)
@Test
public void should_verify_signature_when_verifySignature_called_with_fileName_and_certificate_details_in_verifySignature_method() throws Exception {
PowerMockito.mockStatic(KeyStore.class);
KeyStore keyStoreMock = PowerMockito.mock(KeyStore.class);
PowerMockito.when(KeyStore.getInstance(anyString())).thenReturn(keyStoreMock);
Mockito.doNothing().when(keyStoreMock).load(any(InputStream.class), Mockito.any(char[].class));
Certificate certificateMock = Mockito.mock(Certificate.class);
when(keyStoreMock.getCertificate(anyString())).thenReturn(certificateMock);
PowerMockito.when(KeyStore.getInstance("Windows-MY", "MoonMSCAPI")).thenReturn(keyStoreMock);
boolean result = signatureUtil.verifySignature("src//test//java//Updates.zip.signed.pkcs7"
, "src//test//java//Updates-retrieved.zip", "Windows-MY,MoonMSCAPI,Software View Certificate Authority");
Assert.assertTrue(result);
}
2条答案
按热度按时间qvtsj1bj1#
你可以不使用PowerMock来模拟它,但要用一种稍微复杂一点的方式:
从现在开始你只需mock
keyStoreSpiMock
,例如:svmlkihl2#
发生这种情况的原因是Mockito创建了一个被模拟类的子类,并且父类的方法在
when
调用中被调用。因此,为了防止KeyStoreException,必须将initialized
字段设置为true
,并将keyStoreSpi
设置为非空。@Andremoniy展示了一种实现这一点的方法。然而,我不喜欢模拟
KeyStoreSpi
类,因为我不关心密钥库的内部结构,我想测试的代码也不关心。我使用模拟的原因是将代码视为一个黑盒,只针对API进行测试。为了让keystore mock正常工作,我使用了以下代码:
我使用反射来设置
KeyStore
类的私有字段,并且使用了来自Apache Commons的FieldUtils
,但是您也可以使用普通的Java反射。当然,技术上我也模拟了
KeyStoreSpi
类,但我只是创建了一个没有任何行为的空模拟。这样,我就不需要花任何精力在KeyStore
和KeyStoreSpi
之间的内部API上。