【发布时间】:2021-10-25 09:18:16
【问题描述】:
我需要对从 Azure Blob 存储下载文件的非常简单的方法进行单元测试。 - 下载文件异步。这是全班。
public class BlobStorageService : IBlobStorageService
{
private readonly BlobServiceClient _blobStorageService;
public BlobStorageService(IBlobStorageConnector blobStorageConnector)
{
var connector = blobStorageConnector ?? throw new ArgumentNullException(nameof(blobStorageConnector));
_blobStorageService = connector.GetBlobStorageClient();
}
public async Task<Stream> DownloadFileAsync(string fileName, string containerName)
{
var container = _blobStorageService.GetBlobContainerClient(containerName);
var blob = container.GetBlobClient(fileName);
if (await blob.ExistsAsync())
{
using (var stream = new MemoryStream())
{
await blob.DownloadToAsync(stream);
stream.Position = 0;
return stream;
}
}
return Stream.Null;
}
}
}
问题是它需要大量的模拟。我对测试的想法很陌生,所以这可能是更好的方法。
public class BlobStorageServiceTests
{
private string _containerName = "containerTest";
private string _blobName = "blob";
[Fact]
public async Task BlobStorageService_Should_Return_File()
{
// Arrange
Mock<IBlobStorageConnector> connectorMock = new Mock<IBlobStorageConnector>();
Mock<BlobServiceClient> blobServiceClientMock = new Mock<BlobServiceClient>();
Mock<BlobContainerClient> blobContainerClientMock = new Mock<BlobContainerClient>();
Mock<BlobClient> blobClientMock = new Mock<BlobClient>();
Mock<Response<bool>> responseMock = new Mock<Response<bool>>();
//Preparing result stream
string testString = "testString";
byte[] bytes = Encoding.ASCII.GetBytes(testString);
Stream testStream = new MemoryStream(bytes);
testStream.Position = 0;
responseMock.Setup(x => x.Value).Returns(true);
// this doesn't work, passed stream is not changed, does callback work with value not reference?
blobClientMock.Setup(x => x.DownloadToAsync(It.IsAny<Stream>(), CancellationToken.None)).Callback<Stream, CancellationToken>((stm, token) => stm = testStream);
blobClientMock.Setup(x => x.ExistsAsync(CancellationToken.None)).ReturnsAsync(responseMock.Object);
blobContainerClientMock.Setup(x => x.GetBlobClient(_blobName)).Returns(blobClientMock.Object);
blobServiceClientMock.Setup(x => x.GetBlobContainerClient(_containerName)).Returns(blobContainerClientMock.Object);
connectorMock.Setup(x => x.GetBlobStorageClient()).Returns(blobServiceClientMock.Object);
BlobStorageService blobStorageService = new BlobStorageService(connectorMock.Object); ;
// Act
var result = await blobStorageService.DownloadFileAsync(_blobName, _containerName);
StreamReader reader = new StreamReader(result);
string stringResult = reader.ReadToEnd();
// Assert
stringResult.Should().Contain(testString);
}
}
一切都像一个魅力,只有一小部分测试会导致问题。
确切地说是这部分:
// This callback works
blobClientMock.Setup(x => x.ExistsAsync(CancellationToken.None)).ReturnsAsync(responseMock.Object).Callback(() => Trace.Write("inside job"));
// this doesn't work, does callback not fire?
blobClientMock.Setup(x => x.DownloadToAsync(It.IsAny<Stream>(), CancellationToken.None)).ReturnsAsync(dynamicResponseMock.Object).Callback<Stream, CancellationToken>((stm, token) => Trace.Write("inside stream"));
//Part of tested class where callback should fire
if (await blob.ExistsAsync())
{
using (var stream = new MemoryStream())
{
await blob.DownloadToAsync(stream);
stream.Position = 0;
return stream;
}
}
最后一部分的代码与开头的代码略有不同,我试图只写给 Trace。 “Inside Job”显示得很好,“Inside stream”根本没有。回调没有被触发吗?这里有什么问题?
【问题讨论】:
-
你应该写入提供的流,而不是更改引用(参数不是作为
ref传递的,这怎么可能工作?) -
我已经改变了我的问题,因为它被问得很糟糕。
标签: c# unit-testing testing moq xunit