Home > Blockchain >  JUnit and Mockito unit test for stream.mark(stream.available) when doing S3 putObject
JUnit and Mockito unit test for stream.mark(stream.available) when doing S3 putObject

Time:05-22

I have a method which puts InputStream in s3 bucket.

@Override
    public String putObject(@NonNull String s3BucketName, @NonNull String s3Key, @NonNull String content,
                            @NonNull ObjectMetadata metadataRequest) {
        InputStream stream = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
        try {
            stream.mark(stream.available());
        } catch (IOException e) {
            String errorMessage = String.format("Runtime error while marking stream.",
                    s3BucketName, s3Key);
            throw new RuntimeException(errorMessage, e);
        }
        PutObjectRequest request = new PutObjectRequest(s3BucketName, s3Key, stream, metadataRequest);
        return putObject(request);
    }

I want to make the method cause IOException and then throw RuntimeException and I have written the unit test for the same.

@Test
    public void putObjectTest_withStringContent_withMetadataRequest_IOError() {
        ObjectMetadata metadataRequest = new ObjectMetadata();
        metadataRequest.addUserMetadata(TEST_METADATA_KEY, TEST_METADATA_VALUE);
        InputStream mockStream = Mockito.mock(InputStream.class);
        Mockito.when(mockStream.mark(mockStream.available())).thenThrow(IOException.class);

        assertThrows(RuntimeException.class, () -> s3Accessor.putObject
                (TEST_S3BUCKET, TEST_S3OBJECT, TEST_STRING, metadataRequest));
    }

This is what I have tried but this is showing error in editor

Required type:
T
Provided:
void
reason: no instance(s) of type variable(s) T exist so that void conforms to T

How can I make the method throw IOException?

CodePudding user response:

stream is a ByteArrayInputStream. That will never ever ever throw any exception when mark is called. The documentation clearly states that no IOException can be thrown, and that the argument is ignored.

The exception doesn't come from the mark call, it comes from the available call. As the argument is ignored, just replace it with 0, and you don't need to catch the IOException. In fact, you'll get a compiler error:

exception java.io.IOException is never thrown in body of corresponding try statement

CodePudding user response:

stream.mark(...) will never throw any checked exceptions anyway so this is rather pointless.

You also don't need to mark or reset the stream manually at all. The SDK does that behind the scenes.

By default, the AWS SDK for Java attempts to retry failed transfers by marking the input stream before the start of a transfer and then resetting it before retrying.

If your stream is larger than 128 KB, then you may need to call setReadLimit to 1 byte greater than the size of the stream to avoid a ResetException when not using a FileInputStream. If it isn't, then you don't need to do anything. Regardless, you don't need to mark or reset the stream yourself.

However, for reference purposes, Mockito.when(...).thenThrow(...) is for method invocations that return a value.

stream.mark(mockStream.available()) is a method invocation that does not return a value (void return type).

As per docs:

Use doThrow() when you want to stub the void method with an exception.

In this case, replace:

Mockito.when(mockStream.mark(mockStream.available())).thenThrow(IOException.class);

With:

doThrow(IOException.class).when(mockStream).mark(mockStream.available());
  • Related