繁体   English   中英

在Mockito中使用doNothing()的非void方法?

[英]Non-void method with doNothing() in Mockito?

我有一个单元测试,用于测试将文件上传到GCP存储。 这是上传文件的代码。

@Override
public boolean upload(StorageConfiguration storageConfiguration, File file) throws MetaFeedException {
    // get google storage connection.
    Optional<Storage> storage = getStorageConnection(storageConfiguration.getJsonCredentialFilePath());

    // if GCP storage is empty, return empty.
    if (!storage.isPresent()) {
        throw new MetaFeedException("Failed to establish connection with GCP storage");
    }

    // upload blob with given file content
    BlobId blobId = BlobId.of(storageConfiguration.getBucketName(),
            storageConfiguration.getBucketPath().concat(file.getName()));
    BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType(storageConfiguration.getContentType()).build();
    try {
        return storage.get().create(blobInfo, Files.readAllBytes(Paths.get(file.getAbsolutePath()))).exists();
    } catch (Exception e) {
        throw new MetaFeedException("Error occurred while uploading file.", e);
    }
}

在单元测试中,我做了类似的事情,

@Test
public void should_upload_file_to_gcp_with_given_data() throws Exception {
    File tempFile = File.createTempFile("file-name", "1");

    StorageConfiguration storageConfiguration = new StorageConfiguration();
    storageConfiguration.setBucketName("sample-bucket");
    storageConfiguration.setBucketPath("ff/");
    storageConfiguration.setJsonCredentialFilePath("json-credentials");
    storageConfiguration.setContentType("text/plain");

    StorageOptions defaultInstance = mock(StorageOptions.class);
    Storage mockStorage = spy(Storage.class);

    when(defaultInstance.getService()).thenReturn(mockStorage);

    BlobId blobId = BlobId.of(storageConfiguration.getBucketName(), storageConfiguration.getBucketPath().concat(tempFile.getName()));
    BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType(storageConfiguration.getContentType()).build();

    doNothing().when(mockStorage).create(blobInfo, Files.readAllBytes(Paths.get(tempFile.getAbsolutePath())));

    boolean upload = gcpStorageManager.upload(storageConfiguration, tempFile);
    Assert.assertTrue(upload);
}

我正在尝试做的是防止调用create()方法。 我的观点是,我不想将其真正上传到GCP,因为这是一项测试。 所以我尝试了如上所述。 但是我有一个错误

org.mockito.exceptions.base.MockitoException: 
Only void methods can doNothing()!
Example of correct use of doNothing():
    doNothing().
    doThrow(new RuntimeException())
    .when(mock).someVoidMethod();
 Above means:
someVoidMethod() does nothing the 1st time but throws an exception 
the 2nd time is called

UPDATE

Optional<Storage> storage;
    try {
        //connect with the json key file if the key path is not empty
        if (StringUtils.isNotEmpty(jsonCredentialFilePath) && Files.exists(Paths.get(jsonCredentialFilePath))) {
            storage = Optional.ofNullable(StorageOptions.newBuilder()
                    .setCredentials(ServiceAccountCredentials.fromStream(new FileInputStream(jsonCredentialFilePath)))
                    .build().getService());
        } else {
            // if no json key file provided connect to storage without key file.
            storage = Optional.ofNullable(StorageOptions.getDefaultInstance().getService());
        }
    } catch (Exception e) {
        throw new MetaFeedException("Error occurred while connecting to GCP storage", e);
    }

    return storage;

有没有办法解决将文件上传到GCP的测试?

错误消息中描述了实际的问题: Only void methods can doNothing()

create()方法不是无效的,因此无法使用doNoting()对其进行模拟,因此必须使用doReturn来代替。 在这种情况下,您可以返回Blob的模拟:

Blob mockBlob = mock(Blob.class);
when(mockBlob.exists()).thenReturn(true);
doReturn(mockBlob).when(mockStorage).create(blobInfo, Files.readAllBytes(Paths.get(tempFile.getAbsolutePath())));

这是第一个错误。 第二,看起来您没有将间谍对象注入被测对象。 您的方法getStorageConnection()会在您调用Storage时创建一个新实例,并且不考虑间谍对象。 因此,您在StorageOptions.class但是StorageOptions.getDefaultInstance()方法对这个StorageOptions.getDefaultInstance()对象一无所知。

因此,在这里我可以看到两种解决问题的方法。 第一个,对我来说,更可取的是将依赖注入到方法或类中。 对方法的依赖注入:

@Override
public boolean upload(Storage storage, File file) throws MetaFeedException {

但是,事实并非如此,只要您的方法覆盖了某些接口(如我所假设的那样)。 因此,您可以将方法getStorageConnection移至单独的类StorageProvider并将其实例注入您的类,然后在测试中可以模拟StorageProvider以返回Storagespy 在上载方法中,您将调用:

Optional<Storage> storage = storageProvider.getStorageConnection(storageConfiguration.getJsonCredentialFilePath());

第二个路径是解决方法,它是使方法getStorageConnection受保护,并在测试中覆盖它以返回一个受监视的对象。 在您的测试中:

gcpStorageManager = new GcpStorageManager() {
  @Override
  protected Storage getStorageConnection(...) {
    return mockedStorage;
  }
}

我有以下问题:我有一个返回Page <...>的方法,但是我只能在void方法上使用doNothing(),所以修复很容易:

    @Override
    public Page<ThreadServiceModel> findAll(Pageable pageable) {
        return this.findAll(ThreadServiceModel.class, pageable);
    }

现在我们开始:

        //Will fail and the actualy findAll will be invoked:
        when(this.threadServices.findAll(ThreadServiceModel.class,pageable)).thenReturn(null);

        //Will fail ,cuz you cannot call doNothing() on something that returns values

        doNothing().when(this.threadServices).findAll(ThreadServiceModel.class,pageable);

        //This is the solution ,and when you use doReturn() the actual method will be NOT invoked,
        //+In my case i dont need value , but if i want I cant use...
        doReturn(null).when(this.threadServices).findAll(ThreadServiceModel.class,pageable);

所以解决方案很简单,请在我向您展示的代码上使用最后一种方法:)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM