【问题标题】:I want to mock a proprietary class that extends InputStream, mock read, verify close我想模拟一个扩展 InputStream 的专有类,模拟读取,验证关闭
【发布时间】:2015-03-20 22:16:36
【问题描述】:

我想使用 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);

以某种方式模拟读取方法

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


    【解决方案1】:

    您可以使用 Mockito's Answer 来模拟流。

        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。希望对您有所帮助。

    【讨论】:

    • 正是我想要的!
    【解决方案2】:

    你可以通过一种简单的方式让它工作:

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

    也就是说,现在,您正在嘲笑亚马逊的实施。这意味着如果任何方法变成 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 之间的差距。

    【讨论】:

      【解决方案3】:

      在内部,S3ObjectInputStream 是对 InputStream 的抽象。所以在我看来,你可以嘲笑同样的事情。代码看起来像这样

      String expected = "This is a dummy mocked content";
      InputStream inputStream = IOUtils.toInputStream(expected);
      S3ObjectInputStream s3Input = new S3ObjectInputStream(inputStream,null);
      S3Object s3Object = mock(S3Object.class);
      AmazonS3Client amazonS3Client = mock(AmazonS3Client.class);
      S3AttachmentsService service = new S3AttachmentsService(amazonS3Client);
      when(amazonS3Client.getObject(any(GetObjectRequest.class)).thenReturn(s3Object);
      when(s3Object.getObjectContent).thenReturn(s3Input);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-18
        • 1970-01-01
        • 2021-03-15
        • 1970-01-01
        相关资源
        最近更新 更多