我想模拟一个扩展InputStream的专有类,模拟读取,验证关闭

问题描述 投票:0回答:2

我想使用Mockito模拟AmazonS3并测试从中打开流然后从我的代码中读取后验证流已关闭。我也想从流中读取字节。像这样的东西:

    AmazonS3 client = mock(AmazonS3.class);
        when(tm.getAmazonS3Client()).thenReturn(client);
        S3Object response = mock(S3Object.class); 
        when(client.getObject(any(GetObjectRequest.class))).thenReturn(response);
        S3ObjectInputStream stream = mock(S3ObjectInputStream.class); 
        when(response.getObjectContent()).thenReturn(stream);

somehow mock the read method

MyObject me = new MyObject(client);
byte[] bra me.getBytes(File f, offset, length);
assertEquals(length, bra.length);
verify(stream).close();
java unit-testing inputstream mockito
2个回答
2
投票

您可能可以通过简单的方式使它起作用:

when(stream.read()).thenReturn(0, 1, 2, 3 /* ... */);

也就是说,您现在正在嘲笑Amazon的实现。这意味着,如果任何一种方法都变为final方法,那么您将处境不佳,因为由于编译器的限制,Mockito不支持模拟final方法。您不拥有的模拟类型很诱人,但可能会导致损坏。

如果您的目标是测试getBytes返回正确的值并关闭其流,则更稳定的方法可能是重构为使用任意InputStream:

class MyObject {
  public byte[] getBytes(File f, int offset, int length) {
    /* ... */

    // Delegate the actual call to a getBytes method.
    return getBytes(s3ObjectInputStream, f, offset, length);
  }

  /** Call this package-private delegate in tests with any arbitrary stream. */
  static byte[] getBytes(InputStream s, File f, int offset, int length) {
    /* ... */
  }
}

那时,您可以使用spy(new ByteArrayInputStream(YOUR_BYTE_ARRAY))进行测试,并获得非常引人注目的测试-只需调用verify(stream).close()

沿着这些行,另一种解决方案是添加一个可以控制的接缝,从远处有效地包装getBytes

class MyObject {
  public byte[] getBytes(File f, int offset, int length) {
    /* ... */
    InputStream inputStream = getStream(response.getObjectContent());
    /* ... */
  }

  /** By default, just pass in the stream you already have. */
  InputStream getStream(S3ObjectInputStream s3Stream) {
    return s3Stream;
  }
}

class MyObjectTest {
  @Test public void yourTest() {
    /* ... */
    MyObject myObject = new MyObject(client) {
      /** Instead of returning the S3 stream, insert your own. */
      @Override InputStream getStream() { return yourMockStream; }
    }
    /* ... */
  }
}

不过请记住,您正在正在测试您认为Amazon S3的工作方式,而不是是否在实践中继续工作。如果您的目标是“测试从[S3]打开流”,那么针对实际S3实例运行的集成测试可能是一个好主意,以弥补您的S3模拟和实际S3之间的差距。


0
投票

您可以使用Mockito的答案来模拟流。

    String expectedContents = "Some contents";
    InputStream testInputStream = new StringInputStream(expectedContents);
    S3ObjectInputStream s3ObjectInputStream = mock(S3ObjectInputStream.class);
    S3Object s3Object = mock(S3Object.class);
    AmazonS3Client amazonS3Client = mock(AmazonS3Client.class);
    S3AttachmentsService service = new S3AttachmentsService(amazonS3Client);

    when(s3ObjectInputStream.read(any(byte[].class))).thenAnswer(invocation -> {
        return testInputStream.read(invocation.getArgument(0));
    });

我有一个更广泛的示例here。希望有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.