间谍方法调用实际方法

Spying method calls the actual Method

我正在用 Mockito 编写 JUnit。但是线上

when(encryptDecryptUtil.getKeyFromKeyStore(any(String.class))).thenReturn(keyMock);

它调用了导致测试失败的实际方法。有趣的一点是,当执行 when()...thenReturn() 语句时,它直接在测试用例开始时进行实际调用。你能告诉我如何解决这个问题吗?我的测试如下

@Test
public void testDecryptData_Success() throws NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException {
    encryptDecryptUtil = spy(new EncryptDecryptUtil());
    Key keyMock = Mockito.mock(Key.class);
    when(encryptDecryptUtil.getKeyFromKeyStore(any(String.class))).thenReturn(keyMock);
    String inputData = "TestMessage";
    String version = GetPropValues.getPropValue(PublisherConstants.KEYSTORE_VERSION);
    byte[] enCryptedValue= new byte[] {9,2,5,8,9};
    Cipher cipherMock = Mockito.mock(Cipher.class);
    when(Cipher.getInstance(any(String.class))).thenReturn(cipherMock);
    when(cipherMock.doFinal(any(byte[].class))).thenReturn(enCryptedValue);
    String encryptedMessage = encryptDecryptUtil.encryptData(inputData);
    assert(encryptedMessage.contains(version));
    assertTrue(!encryptedMessage.contains(inputData));
}

在第三行它自己调用了实际的方法。 主要代码如下

public class EncryptDecryptUtil {
private String publicKeyStoreFileName = 

GetPropValues.getPropValue(PublisherConstants.KEYSTORE_PATH);
    private String pubKeyStorePwd = "changeit";
    private static final String SHA1PRNG = "SHA1PRNG";
    private static final String pubKeyAlias="jceksaes";
    private static final String JCEKS = "JCEKS";
    private static final String AES_PADDING = "AES/CBC/PKCS5Padding";
    private static final String AES = "AES";
    private static final int CONST_16 = 16;
    private static final int CONST_0 = 0;
    private static final String KEY_STORE = "aes-keystore";
    private static final String KEY_STORE_TYPE = "jck";
    private static final Logger logger = Logger.getLogger(KafkaPublisher.class);

    public Key getKeyFromKeyStore( String keystoreVersion) {

        KeyStore keyStore = null;
        Key key = null;
        try {
            keyStore = KeyStore.getInstance(JCEKS);
            FileInputStream stream = null;
            stream = new FileInputStream(publicKeyStoreFileName+KEY_STORE+PublisherConstants.UNDERSCORE+keystoreVersion+PublisherConstants.DOT+KEY_STORE_TYPE);
            keyStore.load(stream, pubKeyStorePwd.toCharArray());
            stream.close();
            key = keyStore.getKey(pubKeyAlias, pubKeyStorePwd.toCharArray());
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        catch (FileNotFoundException e) {
            logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
            e.printStackTrace();
        } catch (CertificateException e) {
            logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
            e.printStackTrace();
        } catch (IOException e) {
            logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
            e.printStackTrace();
        }
        return key;
    }

    public String encryptData(String data) {
        String keystoreVersion = GetPropValues.getPropValue(PublisherConstants.KEYSTORE_VERSION);
        SecretKey secKey = new SecretKeySpec(getKeyFromKeyStore(keystoreVersion).getEncoded(), AES);
        String base64EncodedEncryptedMsg = null;
        Cipher cipher = null;

        try { ------- Logic -------------------}
catch() { }
}
}

查看 Spy documentation 的 "Important gotcha on spying real objects" 部分。

基本上,您不能对 Spies 使用 when(...).thenReturn(...) 模式,因为正如您所发现的,它会调用真正的方法!

相反,您使用了完全相同的不同模式:

doReturn(...).when(spy).someMethod();

因此,对于您的示例:

doReturn(keyMock).when(encryptDecryptUtil).getKeyFromKeyStore(any(String.class));

一些与您的问题无关的建议:如果我正确阅读了您的代码,那么 EncryptDecryptUtil 就是您正在测试的 class。作为一般规则,您不应该模拟、存根或监视您实际测试的对象,因为那样您就不是在测试真实的对象。您实际上是在测试由 Mockito 库创建的对象的一个​​版本。此外,这是一种不常见的模式,会使您的测试难以阅读和维护。如果您发现自己必须这样做,那么最好的办法是重构您的代码,以便您正在模拟(或监视)的方法和您正在测试的方法处于不同的 classes.