java 当 Mockito doNothing 方法被调用时,真正的方法被调用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36394482/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 01:23:01  来源:igfitidea点击:

Real method getting called when Mockito doNothing method is called

javaunit-testingmockitopowermockpowermockito

提问by mayooran

I am trying to mock the class KeyStore. After mocking I do not want anything to happen when the load method if it has been called. Therefore I wrote the below lines to achieve this.

我正在尝试模拟 KeyStore 类。在嘲笑之后,我不希望在调用 load 方法时发生任何事情。因此我写了以下几行来实现这一点。

        @PrepareForTest(KeyStoreFactory.class)
        @Test
        public void should_verify_signature_when_verifySignature_called_with_fileName_and_certificate_details_in_verifySignature_method() throws Exception {
            PowerMockito.mockStatic(KeyStoreFactory.class);

            KeyStore keyStoreMock = PowerMockito.mock(KeyStore.class);
            PowerMockito.when(KeyStoreFactory.getInstance(anyString(), anyString())).thenReturn(keyStoreMock);
            Mockito.doNothing().when(keyStoreMock).load(Mockito.any(InputStream.class), Mockito.any(char[].class));
            Certificate certificateMock = Mockito.mock(Certificate.class);
            when(keyStoreMock.getCertificate(anyString())).thenReturn(certificateMock);
            boolean result = signatureUtil.verifySignature("src//test//java//Updates.zip.signed.pkcs7"
                    , "src//test//java//Updates-retrieved.zip", "Windows-MY,SunMSCAPI,someName");
            Assert.assertTrue(result);

        }

But the load method was throwing null pointer exception. Then when I debug I found out that the real method is getting called though I have specified for mockito to not to. What am I doing wrong here? Please advice.

但是加载方法抛出空指针异常。然后当我调试时,我发现真正的方法正在被调用,尽管我已经指定了 mockito 不这样做。我在这里做错了什么?请指教。

Below is the method for which I'm writing the test.

下面是我正在编写测试的方法。

    @Override
        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 = KeyStoreFactory.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 (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;
        }

This is the entire test class :

这是整个测试类:

@RunWith(PowerMockRunner.class)
public class SignatureUtilImplTest {

    SignatureUtilImpl signatureUtil = new SignatureUtilImpl();

@PrepareForTest({KeyStoreFactory.class, SignatureUtilImpl.class})
    @Test
    public void should_verify_signature_when_verifySignature_called_with_fileName_and_certificate_details_in_verifySignature_method() throws Exception {
        CMSSignedDataParser spMock = PowerMockito.mock(CMSSignedDataParser.class);
        SignerInformationVerifier verifierMock = Mockito.mock(SignerInformationVerifier.class);
        SignatureUtilImpl signatureUtilSpy = Mockito.spy(new SignatureUtilImpl());
        KeyStore keyStoreMock = PowerMockito.mock(KeyStore.class);
        PowerMockito.mockStatic(KeyStoreFactory.class);
        PowerMockito.when(KeyStoreFactory.getInstance(anyString(), anyString())).thenReturn(keyStoreMock);
        SignerInformation signerInformationMock = Mockito.mock(SignerInformation.class);
        Collection<SignerInformation> collection = new ArrayList();
        collection.add(signerInformationMock);

        Mockito.doCallRealMethod().when(signatureUtilSpy).verifySignature("src/test/java/Updates.zip.signed.pkcs7"
                , "src/test/java/Updates-retrieved.zip", "Windows-MY,SunMSCAPI,someName");
        Mockito.doNothing().when(signatureUtilSpy).loadKeyStore();
        Mockito.doReturn(verifierMock).when(signatureUtilSpy).getSignerInformationVerifier(anyString(), anyString());
        Mockito.doReturn(spMock).when(signatureUtilSpy).getDataParser(any(DigestCalculatorProvider.class), any(FileInputStream.class));
        Mockito.doReturn(collection).when(spMock).getSignerInfos().getSigners();
        Mockito.doReturn(true).when(signerInformationMock).verify(verifierMock);
        //PowerMockito.doNothing().when(signatureUtilSpy, "verify", any(Path.class),any(Path.class),any(SignerInformationVerifier.class));

//        PowerMockito.doReturn(true).when(signatureUtilSpy, PowerMockito.method(SignatureUtilImpl.class, "verify",Path.class,Path.class, SignerInformationVerifier.class))
//                .withArguments(any(Path.class),any(Path.class),any(SignerInformationVerifier.class));

        boolean result = signatureUtilSpy.verifySignature("src/test/java/Updates.zip.signed.pkcs7"
                , "src/test/java/Updates-retrieved.zip", "Windows-MY,SunMSCAPI,someName");
        Assert.assertTrue(result);
}

}

采纳答案by Sanj

I think this can help :

我认为这可以帮助:

Create another method in SignatureUtil:

在 SignatureUtil 中创建另一个方法:

public KeyStore loadKeyStore(...){
  KeyStore msCertStore = KeyStoreFactory.getInstance(typeOfCertificateStore,certificateStoreProvider);
  msCertStore.load(null, null);
}

In your test class do it like below.

在您的测试课程中,请按照以下方式进行操作。

Mockito.doNothing().when(signatureUtilMock).loadKeyStore(anyString(), anyString());

Here is the code that is working for me

这是对我有用的代码

package com.foo;

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


public class KeyStoreService {
  public KeyStoreService(){

  }

  public void load() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException{
    System.out.println("start");
    KeyStore ks = KeyStore.getInstance("");
    ks.load(null, null);
    System.out.println("end");
 }


}

Test Class

测试班

package com.foo.test;

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

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

import com.foo.KeyStoreService;

@PrepareForTest(KeyStoreService.class)
@RunWith(PowerMockRunner.class)
public class TestKeyStore {

    @Test
    public void test1() throws KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException, CertificateException, IOException{
        PowerMockito.mockStatic(KeyStore.class);
        KeyStore keyStoreMock = PowerMockito.mock(KeyStore.class);
        KeyStoreService kss = new KeyStoreService();
        PowerMockito.when(KeyStore.getInstance(Matchers.anyString(), Matchers.anyString())).thenReturn(keyStoreMock);
        Mockito.doNothing().when(keyStoreMock).load(Mockito.any(InputStream.class), Mockito.any(char[].class));
        kss.load();
    }
}

回答by Arthur Zagretdinov

KeyStoreis a system class, so to mock it the ClassThatCallsTheSystemClassshould be added to @PrepareForTest. As I understand in your case the SignatureUtilImpl should be in @PrepareForTest. But may be another classes is also called this system class.

KeyStore是一个系统类,因此要模拟它,ClassThatCallsTheSystemClass应该将其添加到@PrepareForTest. 据我了解,在您的情况下,SignatureUtilImpl 应该在@PrepareForTest. 但可能还有一个类也叫这个系统类。

By the way, due to how PowerMock mocks system class you may have trouble with cast in this line

顺便说一句,由于 PowerMock 如何模拟系统类,您可能会在这一行中遇到问题

new JcaSimpleSignerInfoVerifierBuilder()
                            .setProvider(certificateStoreProvider)
                            .build(((X509Certificate) msCertStore.getCertificate(certificateName)));

More information you may find hereand here

您可以在此处此处找到更多信息

回答by SaurabhVyas

The following code works for me

以下代码对我有用

PowerMockito.mockStatic(KeyStore.class);
KeyStore mockKeyStore = PowerMockito.mock(KeyStore.class);

PowerMockito.doNothing().when(mockKeyStore).load(Matchers.any(), Matchers.anyObject());
     Mockito.when(KeyStore.getInstance(Matchers.anyString())).thenReturn(mockKeyStore);

回答by Marx.Luo

doNothing() method will calling actual method, if you don't want call, you can use suppress-method.it will suppress no-return method to call.

doNothing() 方法会调用实际的方法,如果你不想调用,你可以使用suppress-method 。它会抑制无返回方法的调用。

doNothing().when(switchMock).finalVoidMethod(channelId);

change

改变

suppress(method(SignatureUtilImpl.class, "loadKeyStore"));