using System.Text; using File.Application.Features.Files.Handlers; using File.Application.Features.Files.Queries; using File.Infrastructure.Storage; using FluentAssertions; using Moq; using Xunit; namespace BuildFlow.File.Tests; /// /// 下载文件查询处理器单元测试。覆盖正常下载、空内容两个场景。 /// Mock IS3StorageService 隔离 S3 外部依赖。 /// public class DownloadFileQueryHandlerTests { /// 创建 Mock S3 + Handler。 private static (Mock s3Mock, DownloadFileQueryHandler handler) Setup(string content = "hello world") { var s3Mock = new Mock(); var stream = new MemoryStream(Encoding.UTF8.GetBytes(content)); s3Mock .Setup(x => x.DownloadFileAsync("test-bucket", "test-key", It.IsAny())) .ReturnsAsync((stream, "text/plain")); var handler = new DownloadFileQueryHandler(s3Mock.Object); return (s3Mock, handler); } [Fact] public async Task DownloadFile_WithValidPath_ReturnsContent() { // Arrange var (s3Mock, handler) = Setup("hello world"); // Act var result = await handler.Handle( new DownloadFileQuery("test-bucket", "test-key"), CancellationToken.None); // Assert result.Should().NotBeNull(); result.Data.Should().NotBeNullOrEmpty(); result.ContentType.Should().Be("application/octet-stream"); s3Mock.Verify(x => x.DownloadFileAsync("test-bucket", "test-key", It.IsAny()), Times.Once); } [Fact] public async Task DownloadFile_S3ReturnsEmpty_ReturnsEmptyArray() { // Arrange — DownloadFileQueryHandler 不校验空内容,直接返回空 byte[] var s3Mock = new Mock(); var emptyStream = new MemoryStream(); s3Mock .Setup(x => x.DownloadFileAsync(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync((emptyStream, "application/octet-stream")); var handler = new DownloadFileQueryHandler(s3Mock.Object); // Act var result = await handler.Handle( new DownloadFileQuery("test-bucket", "test-key"), CancellationToken.None); // Assert — Handler 不做空内容校验,返回空数组 result.Data.Should().NotBeNull(); result.Data.Should().BeEmpty(); } }