gpt4 book ai didi

c# - 如何为单元测试创​​建 HttpContext?

转载 作者:行者123 更新时间:2023-11-30 13:36:05 27 4
gpt4 key购买 nike

我正在努力为我的单元测试模拟所需的 HttpContext

我已经使用 SessionManager 接口(interface)从我的 Mvc Controller 中抽象出对 session 的控制,并使用名为 CookieSessionManager 的类实现了它。 (早期开发阶段)。

CookieSessionManager 通过注入(inject)的单例 HttpContextAccessor(在 Startup.cs ConfigureServices 中)使用 HttpContext

我正在使用在 Startup.cs 中使用 app.UseCookieAuthentication 设置的 Cookie 身份验证。

在 Debug模式下手动测试它会按预期工作

我为我的 AccountController 类编写的 MSUnit 测试与注入(inject)的 MockSessionManager 类一起工作。

我遇到的真正问题是我为我的 CookieSessionManager 类编写的单元测试。我已尝试设置 HttpContext,如下所示;

[TestClass]
public class CookieSessionManagerTest
{
private IHttpContextAccessor contextAccessor;
private HttpContext context;
private SessionManager sessionManager;

[TestInitialize]
public void Setup_CookieSessionManagerTest()
{
context = new DefaultHttpContext();

contextAccessor = new HttpContextAccessor();

contextAccessor.HttpContext = context;

sessionManager = new CookieSessionManager(contextAccessor);
}

错误

但是调用 sessionManager.Login(CreateValidApplicationUser()); 似乎没有设置 IsAuthenticated 标志和测试 CookieSessionManager_Login_ValidUser_Authenticated_isTrue失败。

[TestMethod]
public void CookieSessionManager_Login_ValidUser_Authenticated_isTrue()
{
sessionManager.Login(CreateValidApplicationUser());

Assert.IsTrue(sessionManager.isAuthenticated());
}

public ApplicationUser CreateValidApplicationUser()
{
ApplicationUser applicationUser = new ApplicationUser();

applicationUser.UserName = "ValidUser";

//applicationUser.Password = "ValidPass";

return applicationUser;
}

Test Name: CookieSessionManager_Login_ValidUser_Authenticated_isTrue

: line 43 Test Outcome: Failed Test Duration: 0:00:00.0433169

Result StackTrace: at ClaimsWebAppTests.Identity.CookieSessionManagerTest.CookieSessionManager_Login_ValidUser_Authenticated_isTrue()

CookieSessionManagerTest.cs:line 46 Result Message: Assert.IsTrue failed.

我的代码

session 管理器

using ClaimsWebApp.Models;

namespace ClaimsWebApp.Identity
{
public interface SessionManager
{
bool isAuthenticated();

void Login(ApplicationUser applicationUser);

void Logout();
}
}

CookieSessionManager

using ClaimsWebApp.Identity;
using ClaimsWebApp.Models;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Security.Claims;

namespace ClaimsWebApp
{
public class CookieSessionManager : SessionManager
{
private List<ApplicationUser> applicationUsers;
private IHttpContextAccessor ContextAccessor;
private bool IsAuthenticated;

public CookieSessionManager(IHttpContextAccessor contextAccessor)
{
this.IsAuthenticated = false;

this.ContextAccessor = contextAccessor;

IsAuthenticated = ContextAccessor.HttpContext.User.Identity.IsAuthenticated;

applicationUsers = new List<ApplicationUser>();

applicationUsers.Add(new ApplicationUser { UserName = "ValidUser" });
}
public bool isAuthenticated()
{
return IsAuthenticated;
}

public void Login(ApplicationUser applicationUser)
{
if (applicationUsers.Find(m => m.UserName.Equals(applicationUser.UserName)) != null)
{
var identity = new ClaimsIdentity(new[] {
new Claim(ClaimTypes.Name, applicationUser.UserName)
},
"MyCookieMiddlewareInstance");

var principal = new ClaimsPrincipal(identity);

ContextAccessor.HttpContext.Authentication.SignInAsync("MyCookieMiddlewareInstance", principal);

IsAuthenticated = ContextAccessor.HttpContext.User.Identity.IsAuthenticated;
}
else
{
throw new Exception("User not found");
}
}

public void Logout()
{
ContextAccessor.HttpContext.Authentication.SignOutAsync("MyCookieMiddlewareInstance");

IsAuthenticated = ContextAccessor.HttpContext.User.Identity.IsAuthenticated;
}
}
}

Startup.cs

using ClaimsWebApp.Identity;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace ClaimsWebApp
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<SessionManager, CookieSessionManager>();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();

app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationScheme = "MyCookieMiddlewareInstance",
LoginPath = new PathString("/Account/Unauthorized/"),
AccessDeniedPath = new PathString("/Account/Forbidden/"),
AutomaticAuthenticate = true,
AutomaticChallenge = true
});

app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Account}/{action=Login}/{id?}");
});
}
}
}

CookieSessionManagerTest.cs

using ClaimsWebApp;
using ClaimsWebApp.Identity;
using ClaimsWebApp.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ClaimsWebAppTests.Identity
{
[TestClass]
public class CookieSessionManagerTest
{
private IHttpContextAccessor contextAccessor;
private HttpContext context;
private SessionManager sessionManager;

[TestInitialize]
public void Setup_CookieSessionManagerTest()
{
context = new DefaultHttpContext();

contextAccessor = new HttpContextAccessor();

contextAccessor.HttpContext = context;

sessionManager = new CookieSessionManager(contextAccessor);
}

[TestMethod]
public void CookieSessionManager_Can_Be_Implemented()
{
Assert.IsInstanceOfType(sessionManager, typeof(SessionManager));
}


[TestMethod]
public void CookieSessionManager_Default_Authenticated_isFalse()
{
Assert.IsFalse(sessionManager.isAuthenticated());
}

[TestMethod]
public void CookieSessionManager_Login_ValidUser_Authenticated_isTrue()
{
sessionManager.Login(CreateValidApplicationUser());

Assert.IsTrue(sessionManager.isAuthenticated());
}

public ApplicationUser CreateValidApplicationUser()
{
ApplicationUser applicationUser = new ApplicationUser();

applicationUser.UserName = "ValidUser";

//applicationUser.Password = "ValidPass";

return applicationUser;
}

public ApplicationUser CreateInValidApplicationUser()
{
ApplicationUser applicationUser = new ApplicationUser();

applicationUser.UserName = "InValidUser";

//applicationUser.Password = "ValidPass";

return applicationUser;
}
}
}

最佳答案

不幸的是,几乎不可能用 HttpContext 进行测试。它是一个不使用任何接口(interface)的密封类,因此您不能模拟它。通常,最好的办法是抽象出使用 HttpContext 的代码,然后只测试其他更特定于应用程序的代码。

看起来您已经通过 HttpContextAccessor 完成了此操作,但您没有正确使用它。首先,您公开了 HttpContext 实例,这几乎违背了整个目的。此类应该能够自行返回类似 User.Identity.IsAuthenticated 的内容,例如:httpContextAccessor.IsAuthenticated。在内部,该属性将访问私有(private) HttpContext 实例并只返回结果。

一旦你以这种方式使用它,你就可以模拟 HttpContextAccessor 来简单地返回你测试所需的内容,你不必担心为它提供一个 HttpContext 实例。

诚然,这意味着仍有一些未经测试的代码,即与 HttpContext 一起使用的访问器方法,但这些代码通常非常简单。例如,IsAuthenticated 的代码类似于return httpContext.User.Identity.IsAuthenticated。你要搞砸的唯一方法是如果你粗暴地指责某些东西,但编译器会警告你。

关于c# - 如何为单元测试创​​建 HttpContext?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40284313/

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