Revert "提交"

This reverts commit b96d895809.
This commit is contained in:
2026-02-12 21:59:08 +08:00
parent b96d895809
commit d429560511
339 changed files with 46657 additions and 46655 deletions
+208 -208
View File
@@ -1,208 +1,208 @@
using AutoMapper;
using IM_API.Dtos.Auth;
using IM_API.Dtos.User;
using IM_API.Exceptions;
using IM_API.Interface.Services;
using IM_API.Models;
using IM_API.Services;
using IM_API.Tools;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Moq;
using System;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
public class AuthServiceTests
{
// ---------- 辅助:创建独立的 InMemory DbContext ----------
private ImContext CreateDbContext()
{
var options = new DbContextOptionsBuilder<ImContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
var context = new ImContext(options);
return context;
}
// ---------- 可用于模拟 SaveChanges 抛异常的 DbContext ----------
private class ThrowOnSaveImContext : ImContext
{
private readonly bool _throw;
public ThrowOnSaveImContext(DbContextOptions<ImContext> options, bool throwOnSave) : base(options)
{
_throw = throwOnSave;
}
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
if (_throw) throw new InvalidOperationException("Simulated DB save error");
return base.SaveChangesAsync(cancellationToken);
}
}
// ---------- 默认 AutoMapper(简易映射配置) ----------
private IMapper CreateMapper()
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<RegisterRequestDto, User>();
cfg.CreateMap<User, UserInfoDto>();
});
return config.CreateMapper();
}
// ---------- 创建 Service(允许注入自定义 mapper ----------
private AuthService CreateService(ImContext context, IMapper mapper = null)
{
var loggerMock = new Mock<ILogger<AuthService>>();
var mapperToUse = mapper ?? CreateMapper();
var mockCache = new Mock<ICacheService>();
return new AuthService(context, loggerMock.Object, mapperToUse,mockCache.Object);
}
// --------------------- 测试用例 ---------------------
[Fact]
public async Task LoginAsync_ShouldReturnUser_WhenValidCredentials()
{
var context = CreateDbContext();
context.Users.Add(new User { Id = 1, Username = "Tom", Password = "123456", NickName = "测试用户" });
await context.SaveChangesAsync();
var service = CreateService(context);
var result = await service.LoginAsync(new LoginRequestDto
{
Username = "Tom",
Password = "123456"
});
Assert.NotNull(result);
Assert.Equal(1, result.Id);
Assert.Equal("Tom", result.Username);
}
[Fact]
public async Task LoginAsync_ShouldThrowException_WhenInvalidCredentials()
{
var context = CreateDbContext();
var service = CreateService(context);
await Assert.ThrowsAsync<BaseException>(async () =>
{
await service.LoginAsync(new LoginRequestDto
{
Username = "NotExist",
Password = "wrong"
});
});
}
[Fact]
public async Task LoginAsync_IsCaseSensitive_ForUsername()
{
// 说明:当前实现是精确匹配 => 区分大小写
var context = CreateDbContext();
context.Users.Add(new User { Id = 10, Username = "Tom", Password = "p" });
await context.SaveChangesAsync();
var service = CreateService(context);
// 使用小写用户名应失败(表明当前逻辑区分大小写)
await Assert.ThrowsAsync<BaseException>(async () =>
{
await service.LoginAsync(new LoginRequestDto { Username = "tom", Password = "p" });
});
}
[Fact]
public async Task RegisterAsync_ShouldPersistUserAndReturnDto_WhenNewUser()
{
var context = CreateDbContext();
var service = CreateService(context);
var request = new RegisterRequestDto
{
Username = "Jerry",
Password = "123456"
};
var result = await service.RegisterAsync(request);
// 返回值正确
Assert.NotNull(result);
Assert.Equal("Jerry", result.Username);
Assert.True(result.Id > 0);
// DB 中确实存在该用户
var persisted = await context.Users.FirstOrDefaultAsync(u => u.Username == "Jerry");
Assert.NotNull(persisted);
Assert.Equal("Jerry", persisted.Username);
}
[Fact]
public async Task RegisterAsync_ShouldThrowException_WhenUserExists()
{
var context = CreateDbContext();
context.Users.Add(new User { Username = "Tom", Password = "12223" });
await context.SaveChangesAsync();
var service = CreateService(context);
var request = new RegisterRequestDto { Username = "Tom", Password = "123" };
await Assert.ThrowsAsync<BaseException>(() => service.RegisterAsync(request));
}
[Fact]
public async Task RegisterAsync_ShouldThrow_WhenMapperThrows()
{
var context = CreateDbContext();
var mapperMock = new Mock<IMapper>();
mapperMock.Setup(m => m.Map<User>(It.IsAny<RegisterRequestDto>()))
.Throws(new Exception("mapper failure"));
var service = CreateService(context, mapperMock.Object);
var req = new RegisterRequestDto { Username = "A", Password = "B" };
var ex = await Assert.ThrowsAsync<Exception>(() => service.RegisterAsync(req));
Assert.Contains("mapper failure", ex.Message);
}
[Fact]
public async Task RegisterAsync_ShouldPropagateSaveException_WhenSaveFails()
{
var options = new DbContextOptionsBuilder<ImContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
// 使用自定义上下文在 SaveChanges 时抛异常
var throwingContext = new ThrowOnSaveImContext(options, throwOnSave: true);
var service = CreateService(throwingContext);
var req = new RegisterRequestDto { Username = "X", Password = "P" };
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => service.RegisterAsync(req));
Assert.Contains("Simulated DB save error", ex.Message);
}
[Fact]
public async Task RegisterAsync_NullDto_ThrowsNullReferenceException_CurrentBehavior()
{
// 说明:当前实现没有对 dto 为 null 做检查,会触发 NullReferenceException。
// 建议:在生产代码中改为抛 ArgumentNullException 或者进行参数校验并返回明确错误。
var context = CreateDbContext();
var service = CreateService(context);
await Assert.ThrowsAsync<NullReferenceException>(async () =>
{
await service.RegisterAsync(null);
});
}
}
using AutoMapper;
using IM_API.Dtos.Auth;
using IM_API.Dtos.User;
using IM_API.Exceptions;
using IM_API.Interface.Services;
using IM_API.Models;
using IM_API.Services;
using IM_API.Tools;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Moq;
using System;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
public class AuthServiceTests
{
// ---------- 辅助:创建独立的 InMemory DbContext ----------
private ImContext CreateDbContext()
{
var options = new DbContextOptionsBuilder<ImContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
var context = new ImContext(options);
return context;
}
// ---------- 可用于模拟 SaveChanges 抛异常的 DbContext ----------
private class ThrowOnSaveImContext : ImContext
{
private readonly bool _throw;
public ThrowOnSaveImContext(DbContextOptions<ImContext> options, bool throwOnSave) : base(options)
{
_throw = throwOnSave;
}
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
if (_throw) throw new InvalidOperationException("Simulated DB save error");
return base.SaveChangesAsync(cancellationToken);
}
}
// ---------- 默认 AutoMapper(简易映射配置) ----------
private IMapper CreateMapper()
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<RegisterRequestDto, User>();
cfg.CreateMap<User, UserInfoDto>();
});
return config.CreateMapper();
}
// ---------- 创建 Service(允许注入自定义 mapper ----------
private AuthService CreateService(ImContext context, IMapper mapper = null)
{
var loggerMock = new Mock<ILogger<AuthService>>();
var mapperToUse = mapper ?? CreateMapper();
var mockCache = new Mock<ICacheService>();
return new AuthService(context, loggerMock.Object, mapperToUse,mockCache.Object);
}
// --------------------- 测试用例 ---------------------
[Fact]
public async Task LoginAsync_ShouldReturnUser_WhenValidCredentials()
{
var context = CreateDbContext();
context.Users.Add(new User { Id = 1, Username = "Tom", Password = "123456", NickName = "测试用户" });
await context.SaveChangesAsync();
var service = CreateService(context);
var result = await service.LoginAsync(new LoginRequestDto
{
Username = "Tom",
Password = "123456"
});
Assert.NotNull(result);
Assert.Equal(1, result.Id);
Assert.Equal("Tom", result.Username);
}
[Fact]
public async Task LoginAsync_ShouldThrowException_WhenInvalidCredentials()
{
var context = CreateDbContext();
var service = CreateService(context);
await Assert.ThrowsAsync<BaseException>(async () =>
{
await service.LoginAsync(new LoginRequestDto
{
Username = "NotExist",
Password = "wrong"
});
});
}
[Fact]
public async Task LoginAsync_IsCaseSensitive_ForUsername()
{
// 说明:当前实现是精确匹配 => 区分大小写
var context = CreateDbContext();
context.Users.Add(new User { Id = 10, Username = "Tom", Password = "p" });
await context.SaveChangesAsync();
var service = CreateService(context);
// 使用小写用户名应失败(表明当前逻辑区分大小写)
await Assert.ThrowsAsync<BaseException>(async () =>
{
await service.LoginAsync(new LoginRequestDto { Username = "tom", Password = "p" });
});
}
[Fact]
public async Task RegisterAsync_ShouldPersistUserAndReturnDto_WhenNewUser()
{
var context = CreateDbContext();
var service = CreateService(context);
var request = new RegisterRequestDto
{
Username = "Jerry",
Password = "123456"
};
var result = await service.RegisterAsync(request);
// 返回值正确
Assert.NotNull(result);
Assert.Equal("Jerry", result.Username);
Assert.True(result.Id > 0);
// DB 中确实存在该用户
var persisted = await context.Users.FirstOrDefaultAsync(u => u.Username == "Jerry");
Assert.NotNull(persisted);
Assert.Equal("Jerry", persisted.Username);
}
[Fact]
public async Task RegisterAsync_ShouldThrowException_WhenUserExists()
{
var context = CreateDbContext();
context.Users.Add(new User { Username = "Tom", Password = "12223" });
await context.SaveChangesAsync();
var service = CreateService(context);
var request = new RegisterRequestDto { Username = "Tom", Password = "123" };
await Assert.ThrowsAsync<BaseException>(() => service.RegisterAsync(request));
}
[Fact]
public async Task RegisterAsync_ShouldThrow_WhenMapperThrows()
{
var context = CreateDbContext();
var mapperMock = new Mock<IMapper>();
mapperMock.Setup(m => m.Map<User>(It.IsAny<RegisterRequestDto>()))
.Throws(new Exception("mapper failure"));
var service = CreateService(context, mapperMock.Object);
var req = new RegisterRequestDto { Username = "A", Password = "B" };
var ex = await Assert.ThrowsAsync<Exception>(() => service.RegisterAsync(req));
Assert.Contains("mapper failure", ex.Message);
}
[Fact]
public async Task RegisterAsync_ShouldPropagateSaveException_WhenSaveFails()
{
var options = new DbContextOptionsBuilder<ImContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
// 使用自定义上下文在 SaveChanges 时抛异常
var throwingContext = new ThrowOnSaveImContext(options, throwOnSave: true);
var service = CreateService(throwingContext);
var req = new RegisterRequestDto { Username = "X", Password = "P" };
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => service.RegisterAsync(req));
Assert.Contains("Simulated DB save error", ex.Message);
}
[Fact]
public async Task RegisterAsync_NullDto_ThrowsNullReferenceException_CurrentBehavior()
{
// 说明:当前实现没有对 dto 为 null 做检查,会触发 NullReferenceException。
// 建议:在生产代码中改为抛 ArgumentNullException 或者进行参数校验并返回明确错误。
var context = CreateDbContext();
var service = CreateService(context);
await Assert.ThrowsAsync<NullReferenceException>(async () =>
{
await service.RegisterAsync(null);
});
}
}