模拟openInputStream读取方法

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

我正在从openInputStream中读取大块数据,并想模拟它的读取方法。

 final byte[] testFileData = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0d, 0x0a};

 CloudBlob cloudBlob = this.getCloudBlobContainer().getBlobReferenceFromServer(blobName);

    ByteArrayOutputStream blobStream = new ByteArrayOutputStream();

    try (final InputStream inputStream =  cloudBlob.openInputStream()) {

        //Read 4MB chunks of data 
        byte[] bufferToRead = new byte[4 * 1024 *1024];
        int bytesRead = inputStream.read(bufferToRead );

        while (bytesRead > 0) {
            //Add only the total number of bytes read to Bytearrayoutputstream
            blobStream.write(bufferToRead, 0, bytesRead);
            bytesRead = inputStream.read(bufferToRead);                
        }
    } `

我做了模拟InputStream,但发现很难模仿它的read方法,因为它接受缓冲区作为引用并在读取后将字节数组复制到它。

 @Mock
private BlobInputStream inputStream;


       // Mock
        when(cloudBlobContainer.getBlobReferenceFromServer(anyString())).thenReturn(cloudBlob);
        when(cloudBlob.openInputStream()).thenReturn(inputStream);  
java junit mockito azure-storage powermockito
1个回答
1
投票

InputStream非常难以模拟,尤其是因为它有三个read覆盖以及后来的Java版本中添加的readNBytesreadAllBytes方法。如果使用Mockito完成,您需要让所有这些方法实现与相同的数据交互,否则您最终会遇到一个脆弱的测试,一旦您的实现调用不同的InputStream方法,它就可能会中断。如果你必须使用测试双,你最好写一个“假”,但是当Java内置ByteArrayInputStream时没有理由这样做:你可以构造你的byte[]缓冲区(或者编写一个辅助方法来构造一个您的测试需求)并在测试中将其替换为您的InputStream。这应该足以让任何谈到这个问题的人只是简单地询问一下模拟一个InputStream。

final byte[] testFileData = {
    0x74, 0x65, 0x73, 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0d, 0x0a};
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(testFileData);

不幸的是,这并没有回答关于如何专门为Azure的BlobInputStream提供测试夹具的问题,因为BlobInputStream has a four-arg constructor with a lot of Azure internals特别棘手。好消息是,自1.9.5 Mockito提供了一个delegatesTo method in AdditionalAnswers(我自己强调)记录为:

一个直接将调用转发给委托的答案。代表可能与模拟的类型相同,也可能不同。如果类型不同,则需要在委托类型上找到匹配方法,否则抛出异常。

这意味着您可以通过创建真正的ByteArrayInputStream并将可覆盖的方法委托给它来模拟BlobInputStream。不幸的是,delegatesTo在AdditionalAnswers而不是Answers枚举(并且它需要一个无法在注释中提供的实例参数),因此您需要手动构建模拟:

BlobInputStream mockInputStream = Mockito.mock(
    BlobInputStream.class,
    AdditionalAnswers.delegatesTo(byteArrayInputStream));

when(cloudBlobContainer.getBlobReferenceFromServer(anyString()))
    .thenReturn(cloudBlob);
when(cloudBlob.openInputStream()).thenReturn(mockInputStream);

但是,如果可能,这将是一个很好的机会,可以将代码分成处理Azure输入流的部分与适用于任何InputStream的应用程序代码。例如,如果您的代码采用BlobInputStream并运行解析或纠错代码,则可以将方法handleInputStream(InputStream)分解出来并传入您自己的ByteArrayInputStream以对其进行大量测试。这样可以最大限度地减少模拟BlobInputStream的需要,或者如果您选择仅使用真实后端测试BlobInputStream处理作为集成测试,则可以完全消除它。另请参阅Mocking Files in Java - Mock Contents - Mockito,其中Brice讨论了单元测试和集成测试之间的类似拆分,而不是模拟java.io.File实例。

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