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;
///
/// 资料控制器集成测试
///
public class ProfileControllerIntegrationTests : IClassFixture>
{
private readonly WebApplicationFactory _factory;
private readonly IProfileService _mockProfileService;
public ProfileControllerIntegrationTests(WebApplicationFactory factory)
{
_mockProfileService = Substitute.For();
_factory = factory.WithWebHostBuilder(builder =>
{
builder.UseEnvironment("Testing");
builder.ConfigureServices(services =>
{
services.RemoveAll();
services.AddSingleton(_mockProfileService);
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = TestAuthHandler.AuthenticationScheme;
options.DefaultChallengeScheme = TestAuthHandler.AuthenticationScheme;
})
.AddScheme(
TestAuthHandler.AuthenticationScheme, options => { });
});
});
}
///
/// 测试提交资料 - 未授权返回401
///
[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);
}
///
/// 测试提交资料 - 授权后成功
///
[Fact]
public async Task CreateOrUpdate_WithAuth_ReturnsSuccess()
{
// Arrange
_mockProfileService.CreateOrUpdateAsync(1, Arg.Any())
.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>(content,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(result);
Assert.Equal(0, result.Code);
Assert.Equal(100L, result.Data);
}
///
/// 测试获取我的资料 - 成功
///
[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(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>(content,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(result);
Assert.Equal(0, result.Code);
Assert.NotNull(result.Data);
Assert.Equal(expectedProfile.Nickname, result.Data.Nickname);
}
///
/// 测试获取我的资料 - 资料不存在
///
[Fact]
public async Task GetMyProfile_ProfileNotExists_ReturnsError()
{
// Arrange
_mockProfileService.GetByUserIdAsync(1)
.Returns(Task.FromResult(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>(content,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(result);
Assert.NotEqual(0, result.Code); // 应返回错误码
}
///
/// 测试照片数量限制 - 超过5张返回错误
///
[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>(responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Assert.NotNull(result);
Assert.NotEqual(0, result.Code); // 应返回错误码
}
}