xiangyixiangqin/server/tests/XiangYi.Api.Tests/AppApi/UploadControllerIntegrationTests.cs
2026-01-14 20:23:13 +08:00

307 lines
12 KiB
C#

using System.Net;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using NSubstitute;
using Xunit;
using XiangYi.AppApi;
using XiangYi.Application.DTOs.Responses;
using XiangYi.Infrastructure.Storage;
namespace XiangYi.Api.Tests.AppApi;
/// <summary>
/// 文件上传控制器集成测试
/// </summary>
public class UploadControllerIntegrationTests : IClassFixture<WebApplicationFactory<IAppApiMarker>>
{
private readonly WebApplicationFactory<IAppApiMarker> _factory;
private readonly IStorageProvider _mockStorageProvider;
public UploadControllerIntegrationTests(WebApplicationFactory<IAppApiMarker> factory)
{
_mockStorageProvider = Substitute.For<IStorageProvider>();
_factory = factory.WithWebHostBuilder(builder =>
{
builder.UseEnvironment("Testing");
builder.ConfigureServices(services =>
{
services.RemoveAll<IStorageProvider>();
services.AddSingleton(_mockStorageProvider);
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = TestAuthHandler.AuthenticationScheme;
options.DefaultChallengeScheme = TestAuthHandler.AuthenticationScheme;
})
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(
TestAuthHandler.AuthenticationScheme, options => { });
});
});
}
/// <summary>
/// 测试上传语音文件 - 成功
/// </summary>
[Fact]
public async Task UploadVoice_ValidMp3File_ReturnsSuccess()
{
// Arrange
var expectedFileKey = "voice/test.mp3";
var expectedUrl = "https://example.com/voice/test.mp3";
_mockStorageProvider.UploadAsync(Arg.Any<Stream>(), Arg.Any<string>(), "voice")
.Returns(Task.FromResult(expectedFileKey));
_mockStorageProvider.GetAccessUrl(expectedFileKey, Arg.Any<int>())
.Returns(expectedUrl);
var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
// 创建模拟的 MP3 文件
var content = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("fake mp3 content"));
fileContent.Headers.ContentType = new MediaTypeHeaderValue("audio/mpeg");
content.Add(fileContent, "file", "test.mp3");
// Act
var response = await client.PostAsync("/api/app/upload/voice", content);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseContent = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApiResponse<object>>(responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(result);
Assert.Equal(0, result.Code);
Assert.NotNull(result.Data);
}
/// <summary>
/// 测试上传语音文件 - 不支持的格式
/// </summary>
[Fact]
public async Task UploadVoice_InvalidFormat_ReturnsError()
{
// Arrange
var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
// 创建不支持的文件格式
var content = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("fake content"));
fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
content.Add(fileContent, "file", "test.pdf");
// Act
var response = await client.PostAsync("/api/app/upload/voice", content);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseContent = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApiResponse<object>>(responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(result);
Assert.NotEqual(0, result.Code); // 应返回错误码
}
/// <summary>
/// 测试上传语音文件 - 文件为空
/// </summary>
[Fact]
public async Task UploadVoice_EmptyFile_ReturnsError()
{
// Arrange
var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
var content = new MultipartFormDataContent();
// Act
var response = await client.PostAsync("/api/app/upload/voice", content);
// Assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
/// <summary>
/// 测试上传图片文件 - 成功
/// </summary>
[Fact]
public async Task UploadImage_ValidJpgFile_ReturnsSuccess()
{
// Arrange
var expectedFileKey = "images/test.jpg";
var expectedUrl = "https://example.com/images/test.jpg";
_mockStorageProvider.UploadAsync(Arg.Any<Stream>(), Arg.Any<string>(), "images")
.Returns(Task.FromResult(expectedFileKey));
_mockStorageProvider.GetAccessUrl(expectedFileKey, Arg.Any<int>())
.Returns(expectedUrl);
var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
// 创建模拟的 JPG 文件
var content = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("fake jpg content"));
fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
content.Add(fileContent, "file", "test.jpg");
// Act
var response = await client.PostAsync("/api/app/upload/image", content);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseContent = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApiResponse<object>>(responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(result);
Assert.Equal(0, result.Code);
Assert.NotNull(result.Data);
}
/// <summary>
/// 测试上传图片文件 - 不支持的格式
/// </summary>
[Fact]
public async Task UploadImage_InvalidFormat_ReturnsError()
{
// Arrange
var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
// 创建不支持的文件格式
var content = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("fake content"));
fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
content.Add(fileContent, "file", "test.pdf");
// Act
var response = await client.PostAsync("/api/app/upload/image", content);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseContent = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApiResponse<object>>(responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(result);
Assert.NotEqual(0, result.Code); // 应返回错误码
}
/// <summary>
/// 测试上传语音文件 - 支持的所有格式
/// </summary>
[Theory]
[InlineData("test.mp3", "audio/mpeg")]
[InlineData("test.wav", "audio/wav")]
[InlineData("test.m4a", "audio/mp4")]
[InlineData("test.amr", "audio/amr")]
public async Task UploadVoice_SupportedFormats_ReturnsSuccess(string fileName, string contentType)
{
// Arrange
var expectedFileKey = $"voice/{fileName}";
var expectedUrl = $"https://example.com/voice/{fileName}";
_mockStorageProvider.UploadAsync(Arg.Any<Stream>(), Arg.Any<string>(), "voice")
.Returns(Task.FromResult(expectedFileKey));
_mockStorageProvider.GetAccessUrl(Arg.Any<string>(), Arg.Any<int>())
.Returns(expectedUrl);
var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
var content = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("fake content"));
fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
content.Add(fileContent, "file", fileName);
// Act
var response = await client.PostAsync("/api/app/upload/voice", content);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseContent = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApiResponse<object>>(responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(result);
Assert.Equal(0, result.Code);
}
/// <summary>
/// 测试上传图片文件 - 支持的所有格式
/// </summary>
[Theory]
[InlineData("test.jpg", "image/jpeg")]
[InlineData("test.jpeg", "image/jpeg")]
[InlineData("test.png", "image/png")]
[InlineData("test.gif", "image/gif")]
[InlineData("test.webp", "image/webp")]
public async Task UploadImage_SupportedFormats_ReturnsSuccess(string fileName, string contentType)
{
// Arrange
var expectedFileKey = $"images/{fileName}";
var expectedUrl = $"https://example.com/images/{fileName}";
_mockStorageProvider.UploadAsync(Arg.Any<Stream>(), Arg.Any<string>(), "images")
.Returns(Task.FromResult(expectedFileKey));
_mockStorageProvider.GetAccessUrl(Arg.Any<string>(), Arg.Any<int>())
.Returns(expectedUrl);
var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
var content = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("fake content"));
fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
content.Add(fileContent, "file", fileName);
// Act
var response = await client.PostAsync("/api/app/upload/image", content);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseContent = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApiResponse<object>>(responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(result);
Assert.Equal(0, result.Code);
}
/// <summary>
/// 测试上传文件 - 未授权
/// </summary>
[Fact]
public async Task UploadVoice_NoAuth_ReturnsUnauthorized()
{
// Arrange
var client = _factory.CreateClient();
// 不添加 Authorization 头
var content = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes("fake content"));
fileContent.Headers.ContentType = new MediaTypeHeaderValue("audio/mpeg");
content.Add(fileContent, "file", "test.mp3");
// Act
var response = await client.PostAsync("/api/app/upload/voice", content);
// Assert
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
}