xiangyixiangqin/server/tests/XiangYi.Api.Tests/AppApi/ProfileControllerIntegrationTests.cs
2026-01-02 18:00:49 +08:00

213 lines
7.1 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Net;
using System.Net.Http.Json;
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.Requests;
using XiangYi.Application.DTOs.Responses;
using XiangYi.Application.Interfaces;
namespace XiangYi.Api.Tests.AppApi;
/// <summary>
/// 资料控制器集成测试
/// </summary>
public class ProfileControllerIntegrationTests : IClassFixture<WebApplicationFactory<IAppApiMarker>>
{
private readonly WebApplicationFactory<IAppApiMarker> _factory;
private readonly IProfileService _mockProfileService;
public ProfileControllerIntegrationTests(WebApplicationFactory<IAppApiMarker> factory)
{
_mockProfileService = Substitute.For<IProfileService>();
_factory = factory.WithWebHostBuilder(builder =>
{
builder.UseEnvironment("Testing");
builder.ConfigureServices(services =>
{
services.RemoveAll<IProfileService>();
services.AddSingleton(_mockProfileService);
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = TestAuthHandler.AuthenticationScheme;
options.DefaultChallengeScheme = TestAuthHandler.AuthenticationScheme;
})
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(
TestAuthHandler.AuthenticationScheme, options => { });
});
});
}
/// <summary>
/// 测试提交资料 - 未授权返回401
/// </summary>
[Fact]
public async Task CreateOrUpdate_WithoutAuth_ReturnsUnauthorized()
{
// Arrange
var client = _factory.CreateClient();
var request = new ProfileRequest
{
Relationship = 1,
Surname = "李",
ChildGender = 1
};
// Act
var response = await client.PostAsJsonAsync("/api/app/profile", request);
// Assert
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
/// <summary>
/// 测试提交资料 - 授权后成功
/// </summary>
[Fact]
public async Task CreateOrUpdate_WithAuth_ReturnsSuccess()
{
// Arrange
_mockProfileService.CreateOrUpdateAsync(1, Arg.Any<ProfileRequest>())
.Returns(Task.FromResult(100L));
var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
var request = new ProfileRequest
{
Relationship = 1,
Surname = "李",
ChildGender = 1,
BirthYear = 1995,
Education = 4,
WorkProvince = "广东省",
WorkCity = "深圳市"
};
// Act
var response = await client.PostAsJsonAsync("/api/app/profile", request);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApiResponse<long>>(content,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(result);
Assert.Equal(0, result.Code);
Assert.Equal(100L, result.Data);
}
/// <summary>
/// 测试获取我的资料 - 成功
/// </summary>
[Fact]
public async Task GetMyProfile_WithAuth_ReturnsProfile()
{
// Arrange
var expectedProfile = new ProfileResponse
{
UserId = 1,
Nickname = "李家长(父亲)",
Relationship = 1,
Surname = "李",
ChildGender = 1,
BirthYear = 1995,
Education = 4
};
_mockProfileService.GetByUserIdAsync(1)
.Returns(Task.FromResult<ProfileResponse?>(expectedProfile));
var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
// Act
var response = await client.GetAsync("/api/app/profile");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApiResponse<ProfileResponse>>(content,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(result);
Assert.Equal(0, result.Code);
Assert.NotNull(result.Data);
Assert.Equal(expectedProfile.Nickname, result.Data.Nickname);
}
/// <summary>
/// 测试获取我的资料 - 资料不存在
/// </summary>
[Fact]
public async Task GetMyProfile_ProfileNotExists_ReturnsError()
{
// Arrange
_mockProfileService.GetByUserIdAsync(1)
.Returns(Task.FromResult<ProfileResponse?>(null));
var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
// Act
var response = await client.GetAsync("/api/app/profile");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApiResponse<ProfileResponse>>(content,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(result);
Assert.NotEqual(0, result.Code); // 应返回错误码
}
/// <summary>
/// 测试照片数量限制 - 超过5张返回错误
/// </summary>
[Fact]
public async Task UploadPhotos_ExceedsLimit_ReturnsError()
{
// Arrange
_mockProfileService.CanUploadPhotosAsync(1, 3)
.Returns(Task.FromResult(false)); // 模拟已有3张再上传3张超过限制
var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token-1");
// 创建多文件上传请求
using var content = new MultipartFormDataContent();
for (int i = 0; i < 3; i++)
{
var fileContent = new ByteArrayContent(new byte[] { 0x89, 0x50, 0x4E, 0x47 }); // PNG header
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png");
content.Add(fileContent, "files", $"photo{i}.png");
}
// Act
var response = await client.PostAsync("/api/app/profile/photos", content);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseContent = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApiResponse<UploadPhotoResponse>>(responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(result);
Assert.NotEqual(0, result.Code); // 应返回错误码
}
}