Не пустотный метод с doNothing () в Mockito? - PullRequest
0 голосов
/ 07 декабря 2018

У меня есть модульный тест для проверки загрузки файла в хранилище 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

ОБНОВЛЕНИЕ

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?

Ответы [ 2 ]

0 голосов
/ 05 апреля 2019

У меня была следующая проблема: у меня был метод, который возвращал страницу <...>, но я могу использовать doNothing () только для метода void, поэтому исправить это легко:

    @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);

Итак, решение простое, используйте последний метод кода, который я вам показал:)

0 голосов
/ 07 декабря 2018

Фактическая проблема описана в сообщении об ошибке: 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() ничего не знает об этом смоделированном объекте.

Итак, здесь я вижу два пути решения вашей проблемы.Первый, и он более предпочтителен, как для меня, заключается в том, чтобы ввести зависимость либо в метод, либо в ваш класс.Внедрение зависимости в метод:

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

Но это может быть не так, если ваш метод переопределяет некоторый интерфейс, как я полагаю.Таким образом, вы можете переместить ваш метод getStorageConnection в отдельный класс StorageProvider и внедрить его экземпляр в свой класс, а затем в тесте вы можете смоделировать StorageProvider, чтобы вернуть spy из Storage.В методе загрузки вы будете вызывать:

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

Второй путь, который является довольно обходным, состоит в том, чтобы сделать метод getStorageConnection защищенным и переопределить его в вашем тесте, чтобы вернуть подсмотренный объект.В вашем тесте:

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