gpt4 book ai didi

c# - .NET 核心测试 - 使用 FakeItEasy 模拟 IHttpContextAccessor

转载 作者:太空狗 更新时间:2023-10-30 00:37:46 35 4
gpt4 key购买 nike

我一直在模拟 IHttpContextAccessor 以进行一些 Web API 集成测试。我的目标是能够模拟 IHttpContextAccessor 并返回 NameIdentifier 声明和 RemoteIpAddress。

测试

public class InsertUser : TestBase
{
private UserController _userController;

[OneTimeSetUp]
public void OneTimeSetUp()
{
IStringLocalizer<UserController> localizer = A.Fake<IStringLocalizer<UserController>>();

_userController = new UserController(localizer, Mapper, UserService, StatusService, IdentityService);
_userController.ControllerContext = A.Fake<ControllerContext>();
_userController.ControllerContext.HttpContext = A.Fake<DefaultHttpContext>();

var fakeClaim = A.Fake<Claim>(x => x.WithArgumentsForConstructor(() => new Claim(ClaimTypes.NameIdentifier, "1")));
var fakeIdentity = A.Fake<ClaimsPrincipal>();

A.CallTo(() => fakeIdentity.FindFirst(ClaimTypes.NameIdentifier)).Returns(fakeClaim);
A.CallTo(() => _userController.ControllerContext.HttpContext.User).Returns(fakeIdentity);

StatusTypeEntity statusType = ObjectMother.InsertStatusType(StatusTypeEnum.StatusType.User);
StatusEntity status = ObjectMother.InsertStatus(StatusEnum.Status.Active, statusType);
ObjectMother.InsertUser("FirstName", "LastName", "Email@Email.Email", "PasswordHash", "PasswordSalt", status);
}

public static IEnumerable TestCases
{
get
{
//InsertUser_Should_Insert
yield return new TestCaseData(new InsertUserModel
{
FirstName = "FirstName",
LastName = "LastName",
StatusId = 1,
Email = "Email2@Email.Email"
},
1,
2).SetName("InsertUser_Should_Insert");

//InsertUser_Should_Not_Insert_When_StatusId_Not_Exist
yield return new TestCaseData(new InsertUserModel
{
FirstName = "FirstName",
LastName = "LastName",
StatusId = int.MaxValue,
Email = "Email2@Email.Email"
},
1,
1).SetName("InsertUser_Should_Not_Insert_When_StatusId_Not_Exist");

//InsertUser_Should_Not_Insert_When_Email_Already_Exist
yield return new TestCaseData(new InsertUserModel
{
FirstName = "FirstName",
LastName = "LastName",
StatusId = 1,
Email = "Email@Email.Email"
},
1,
1).SetName("InsertUser_Should_Not_Insert_When_Email_Already_Exist");
}
}

[Test, TestCaseSource(nameof(TestCases))]
public async Task Test(InsertUserModel model, int userCountBefore, int userCountAfter)
{
//Before
int resultBefore = Database.User.Count();

resultBefore.ShouldBe(userCountBefore);

//Delete
await _userController.InsertUser(model);

//After
int resultAfter = Database.User.Count();

resultAfter.ShouldBe(userCountAfter);
}
}

Controller

[Route("api/administration/[controller]")]
[Authorize(Roles = "Administrator")]
public class UserController : Controller
{
private readonly IStringLocalizer<UserController> _localizer;
private readonly IMapper _mapper;
private readonly IUserService _userService;
private readonly IStatusService _statusService;
private readonly IIdentityService _identityService;

public UserController(IStringLocalizer<UserController> localizer,
IMapper mapper,
IUserService userService,
IStatusService statusService,
IIdentityService identityService)
{
_localizer = localizer;
_mapper = mapper;
_userService = userService;
_statusService = statusService;
_identityService = identityService;
}

[HttpPost("InsertUser")]
public async Task<IActionResult> InsertUser([FromBody] InsertUserModel model)
{
if (model == null || !ModelState.IsValid)
{
return Ok(new GenericResultModel(_localizer["An_unexpected_error_has_occurred_Please_try_again"]));
}

StatusModel status = await _statusService.GetStatus(model.StatusId, StatusTypeEnum.StatusType.User);

if (status == null)
{
return Ok(new GenericResultModel(_localizer["Could_not_find_status"]));
}

UserModel userExist = await _userService.GetUser(model.Email);

if (userExist != null)
{
return Ok(new GenericResultModel(_localizer["Email_address_is_already_in_use"]));
}

UserModel user = _mapper.Map<InsertUserModel, UserModel>(model);

var letrTryAndGetUserIdFromNameIdentifier = _identityService.GetUserId();

user.DefaultIpAddress = _identityService.GetIpAddress();

//UserModel insertedUser = await _userService.InsertUser(user, model.Password);
UserModel insertedUser = await _userService.InsertUser(user, "TODO");

if (insertedUser != null)
{
return Ok(new GenericResultModel { Id = insertedUser.Id });
}

return Ok(new GenericResultModel(_localizer["Could_not_create_user"]));
}
}

这里重要的一行是:

var letrTryAndGetUserIdFromNameIdentifier = _identityService.GetUserId();

身份服务

public class IdentityService : IIdentityService
{
private readonly IHttpContextAccessor _httpContextAccessor;

public IdentityService(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}

public int GetUserId()
{
if (_httpContextAccessor.HttpContext == null || !Authenticated())
{
throw new AuthenticationException("User is not authenticated.");
}

ClaimsPrincipal claimsPrincipal = _httpContextAccessor.HttpContext.User;

string userIdString = claimsPrincipal.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
int.TryParse(userIdString, out int userIdInt);

return userIdInt;
}

public string GetIpAddress()l
{
return _httpContextAccessor.HttpContext?.Connection.RemoteIpAddress.ToString();
}
}

这里失败了:

if (_httpContextAccessor.HttpContext == null || !Authenticated())
{
throw new AuthenticationException("User is not authenticated.");
}

目前 _httpContextAccessor.HttpContext 始终为空。我不确定我在这里的道路是否正确..

最佳答案

对于这种测试,您最好编写一个使用 TestHost 类型的集成测试,并尽可能少地进行模拟。它会简单得多,并且您将能够测试您当前的方法不支持的过滤器(如路由和授权规则)。您可以在此处的文档中阅读更多内容: https://learn.microsoft.com/en-us/aspnet/core/testing/integration-testing

作为我关于 ASP.NET Core Filters 的 MSDN 文章的一部分,我有一个很好的示例展示了如何编写 API 测试,这里是: https://msdn.microsoft.com/en-us/magazine/mt767699.aspx

关于c# - .NET 核心测试 - 使用 FakeItEasy 模拟 IHttpContextAccessor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45110548/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com