Razor Pages .NET Core 2.1 Integration Testing post authentication

三世轮回 提交于 2019-12-24 10:55:33

问题


I am looking for some guidance...

I'm currently looking at trying to write some integration tests for a Razor Pages app in .net core 2.1, the pages I'm wanting to test are post authentication but I'm not sure about the best way of approaching it. The docs seem to suggest creating a CustomWebApplicationFactory, but apart from that I've got a little bit lost as how I can fake/mock an authenticated user/request, using basic cookie based authentication.

I've seen that there is an open GitHub issue against the Microsoft docs (here is the actual GitHub issue), there was a mentioned solution using IdentityServer4 but I’m just looking how to do this just using cookie based authentication.

Has anyone got any guidance they may be able to suggest?

Thanks in advance

My Code so far is:

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
        {
            services.AddDbContext<ApplicationDbContext>(options =>
            {
                options.UseMySql(connectionString);
                options.EnableSensitiveDataLogging();
            });

            services.AddLogging(builder =>
            {
                builder.AddSeq();
            });

            services.ConfigureAuthentication();
            services.ConfigureRouting();
    }
}

ConfigureAuthentication.cs

  namespace MyCarparks.Configuration.Startup
  {
      public static partial class ConfigurationExtensions
      {
          public static IServiceCollection ConfigureAuthentication(this IServiceCollection services)
          {
              services.AddIdentity<MyCarparksUser, IdentityRole>(cfg =>
              {
                  //cfg.SignIn.RequireConfirmedEmail = true;
              })
              .AddDefaultUI()
              .AddDefaultTokenProviders()
              .AddEntityFrameworkStores<ApplicationDbContext>();

              services.ConfigureApplicationCookie(options =>
              {
                  options.LoginPath = $"/Identity/Account/Login";
                  options.LogoutPath = $"/Identity/Account/Logout";
                  options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
              });

              services.AddMvc()
                  .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
                  .AddRazorPagesOptions(options =>
              {
                    options.AllowAreas = true;
                    options.Conventions.AuthorizeAreaFolder("Identity", "/Account/Manage");
                    options.Conventions.AuthorizeAreaPage("Identity", "/Account/Logout");

                    options.Conventions.AuthorizeFolder("/Sites");
                });

            return services;
        }
    }
}

Integration Tests

PageTests.cs

namespace MyCarparks.Web.IntegrationTests
{
    public class PageTests : IClassFixture<CustomWebApplicationFactory<Startup>>
    {
        private readonly CustomWebApplicationFactory<Startup> factory;

        public PageTests(CustomWebApplicationFactory<Startup> webApplicationFactory)
        {
            factory = webApplicationFactory;
        }


    [Fact]
    public async Task SitesReturnsSuccessAndCorrectContentTypeAndSummary()
    {
        var siteId = Guid.NewGuid();
        var site = new Site { Id = siteId, Address = "Test site address" };
        var mockSite = new Mock<ISitesRepository>();
        mockSite.Setup(s => s.GetSiteById(It.IsAny<Guid>())).ReturnsAsync(site);

        // Arrange
        var client = factory.CreateClient();

        // Act
        var response = await client.GetAsync("http://localhost:44318/sites/sitedetails?siteId=" + siteId);

        // Assert
        response.EnsureSuccessStatusCode();

        response.Content.Headers.ContentType.ToString()
            .Should().Be("text/html; charset=utf-8");

        var responseString = await response.Content.ReadAsStringAsync();
        responseString.Should().Contain("Site Details - MyCarparks");
    }

    public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<Startup>
    {
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {
            builder.UseStartup<Startup>();
        }
    }
}

回答1:


For implement your requirement, you could try code below which creates the client with the authentication cookies.

    public class CustomWebApplicationFactory<TEntryPoint> : WebApplicationFactory<TEntryPoint> where TEntryPoint : class
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(services =>
        {

        });
        base.ConfigureWebHost(builder);
    }
    public new HttpClient CreateClient()
    {
        var cookieContainer = new CookieContainer();
        var uri = new Uri("https://localhost:44344/Identity/Account/Login");
        var httpClientHandler = new HttpClientHandler
        {
            CookieContainer = cookieContainer
        };
        HttpClient httpClient = new HttpClient(httpClientHandler);
        var verificationToken = GetVerificationToken(httpClient, "https://localhost:44344/Identity/Account/Login");
        var contentToSend = new FormUrlEncodedContent(new[]
                {
                            new KeyValuePair<string, string>("Email", "test@outlook.com"),
                            new KeyValuePair<string, string>("Password", "1qaz@WSX"),
                            new KeyValuePair<string, string>("__RequestVerificationToken", verificationToken),
                        });
        var response = httpClient.PostAsync("https://localhost:44344/Identity/Account/Login", contentToSend).Result;
        var cookies = cookieContainer.GetCookies(new Uri("https://localhost:44344/Identity/Account/Login"));
        cookieContainer.Add(cookies);
        var client = new HttpClient(httpClientHandler);
        return client;
    }
    private string GetVerificationToken(HttpClient client, string url)
    {
        HttpResponseMessage response = client.GetAsync(url).Result;
        var verificationToken =response.Content.ReadAsStringAsync().Result;
        if (verificationToken != null && verificationToken.Length > 0)
        {
            verificationToken = verificationToken.Substring(verificationToken.IndexOf("__RequestVerificationToken"));
            verificationToken = verificationToken.Substring(verificationToken.IndexOf("value=\"") + 7);
            verificationToken = verificationToken.Substring(0, verificationToken.IndexOf("\""));
        }
        return verificationToken;
    }
}


来源:https://stackoverflow.com/questions/52954724/razor-pages-net-core-2-1-integration-testing-post-authentication

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!