[英]C# MVC How Do I Write An Integration Test That Makes Sure Attempting To Register A New User Redirects To The Correct Page?
[英]C# How Do I Logout in An Integration Test for An MVC App?
我有一個 MVC 應用程序,我正在為其編寫集成測試。 我有一個我正在測試的過程,涉及用戶注銷然后登錄。我可以登錄就好了。 下面的測試成功(順便說一句,我在 memory db 中注入了一個匹配的用戶條目):
[Fact]
public async Task D_LoginTest()
{
var client = _factory.CreateClient(
new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = true
});
var initResponse = await client.GetAsync("/Identity/Account/Login");
var antiForgeryValues = await AntiForgeryTokenExtractor.ExtractAntiForgeryValues(initResponse);
var postRequest = new HttpRequestMessage(HttpMethod.Post, "/Identity/Account/Login");
postRequest.Headers.Add("Cookie", new CookieHeaderValue(AntiForgeryTokenExtractor.AntiForgeryCookieName, antiForgeryValues.cookieValue).ToString());
var formModel = new Dictionary<string, string>
{
{ AntiForgeryTokenExtractor.AntiForgeryFieldName, antiForgeryValues.fieldValue },
{ "Input.Email", "test@example.com" },
{ "Input.Password", "pas3w0!rRd" }
};
postRequest.Content = new FormUrlEncodedContent(formModel);
var response = await client.SendAsync(postRequest);
response.EnsureSuccessStatusCode();
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
但是當我在這個測試中添加注銷時:
[Fact]
public async Task D_LoginTest()
{
var client = _factory.CreateClient(
new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = true
});
var initResponse = await client.GetAsync("/Identity/Account/Login");
var antiForgeryValues = await AntiForgeryTokenExtractor.ExtractAntiForgeryValues(initResponse);
var postRequest = new HttpRequestMessage(HttpMethod.Post, "/Identity/Account/Login");
postRequest.Headers.Add("Cookie", new CookieHeaderValue(AntiForgeryTokenExtractor.AntiForgeryCookieName, antiForgeryValues.cookieValue).ToString());
var formModel = new Dictionary<string, string>
{
{ AntiForgeryTokenExtractor.AntiForgeryFieldName, antiForgeryValues.fieldValue },
{ "Input.Email", "test@example.com" },
{ "Input.Password", "pas3w0!rRd" }
};
postRequest.Content = new FormUrlEncodedContent(formModel);
var response = await client.SendAsync(postRequest);
response.EnsureSuccessStatusCode();
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var postRequestLogout = new HttpRequestMessage(HttpMethod.Post, "/Identity/Account/Logout");
postRequestLogout.Headers.Add("Cookie", new CookieHeaderValue(AntiForgeryTokenExtractor.AntiForgeryCookieName, antiForgeryValues.cookieValue).ToString());
var postRequestLougoutForm = new Dictionary<string, string>
{
{ AntiForgeryTokenExtractor.AntiForgeryFieldName, antiForgeryValues.fieldValue },
};
postRequestLogout.Content = new FormUrlEncodedContent(postRequestLougoutForm);
var logoutAnswer = await client.SendAsync(postRequestLogout);
logoutAnswer.EnsureSuccessStatusCode();
Console.WriteLine(logoutAnswer.StatusCode);
Assert.Equal(HttpStatusCode.OK, logoutAnswer.StatusCode);
}
它失敗並出現此錯誤。
Failed amaranth.Tests.AdminControllerTests.D_LoginTest [23 ms]
Error Message:
System.Net.Http.HttpRequestException : Response status code does not indicate success: 400 (Bad Request).
Stack Trace:
at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
at amaranth.Tests.AdminControllerTests.D_LoginTest() in /path/to/project/dir/amaranth.Tests/IntegrationTests/AdminControllerTests.cs:line 308
--- End of stack trace from previous location ---
另外,如果它有幫助,這是 Logout.cshtml.cs 文件:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace amaranth.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class LogoutModel : PageModel
{
private readonly SignInManager<IdentityUser> _signInManager;
private readonly ILogger<LogoutModel> _logger;
public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
public void OnGet()
{
}
public async Task<IActionResult> OnPost(string returnUrl = null)
{
await _signInManager.SignOutAsync();
_logger.LogInformation("User logged out.");
if (returnUrl != null)
{
return LocalRedirect(returnUrl);
}
else
{
return Page();
}
}
}
}
我究竟做錯了什么? 如何在集成測試中注銷? 順便說一句,如果有幫助,這是默認的 Razor Page MVC 腳手架注銷。
我創建了一個最小的可重現示例amaranth-minal-testing-example
,它在集成測試中成功注銷。 首先這是amaranth-minal-testing-example/TestRunProject.Tests/AntiForgeryTokenExtractor.cs
using System.Text.RegularExpressions;
using Microsoft.Net.Http.Headers;
namespace TestRunProject.Tests
{
public static class AntiForgeryTokenExtractor
{
public static string ExtractAntiForgeryToken(string htmlBody)
{
var requestVerificationTokenMatch =
Regex.Match(htmlBody, $@"\<input name=""__RequestVerificationToken"" type=""hidden"" value=""([^""]+)"" \/\>");
if (requestVerificationTokenMatch.Success)
return requestVerificationTokenMatch.Groups[1].Captures[0].Value;
throw new ArgumentException($"Anti forgery token '__RequestVerificationToken' not found in HTML", nameof(htmlBody));
}
}
}
這是amaranth-minal-testing-example/TestRunProject.Tests/IntegrationTests/AuthTest.cs
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Net.Http.Headers;
using Microsoft.VisualStudio.TestPlatform.TestHost;
namespace TestRunProject.Tests
{
public class AuthTests
{
[Fact]
public async Task DLoginTest()
{
{
var application = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
// ... Configure test services
});
var client = application.CreateClient();
// -- REGISTER --
var registerResponse = await client.GetAsync("/Identity/Account/Register");
registerResponse.EnsureSuccessStatusCode();
string registerResponseContent = await registerResponse.Content.ReadAsStringAsync();
var requestVerificationToken = AntiForgeryTokenExtractor.ExtractAntiForgeryToken(registerResponseContent);
var formModel = new Dictionary<string, string>
{
{ "Input.Email", "test2@example.com" },
{ "Input.Password", "pas3w02!rRd" },
{ "Input.ConfirmPassword", "pas3w02!rRd" },
{ "__RequestVerificationToken", requestVerificationToken },
};
var postRequest2 = new HttpRequestMessage(HttpMethod.Post, "/Identity/Account/Register");
postRequest2.Content = new FormUrlEncodedContent(formModel);
var registerResponse2 = await client.SendAsync(postRequest2);
registerResponse2.EnsureSuccessStatusCode();
// -- LOGOUT --
var logoutRequest = new StringContent("");
logoutRequest.Headers.Add("RequestVerificationToken", requestVerificationToken);
var logoutResponse = await client.PostAsync("/Identity/Account/Logout", logoutRequest);
logoutResponse.EnsureSuccessStatusCode();
// -- LOGIN --
var loginResponse = await client.GetAsync("/Identity/Account/Login");
loginResponse.EnsureSuccessStatusCode();
string loginResponseContent = await registerResponse.Content.ReadAsStringAsync();
requestVerificationToken = AntiForgeryTokenExtractor.ExtractAntiForgeryToken(loginResponseContent);
formModel = new Dictionary<string, string>
{
{ "Input.Email", "test2@example.com" },
{ "Input.Password", "pas3w02!rRd" },
{ "__RequestVerificationToken", requestVerificationToken },
};
var loginRequest = new HttpRequestMessage(HttpMethod.Post, "/Identity/Account/Login");
loginRequest.Content = new FormUrlEncodedContent(formModel);
var loginResponse2 = await client.SendAsync(loginRequest);
loginResponse2.EnsureSuccessStatusCode();
}
}
}
}
This works for a default scaffolded C# ASP.NET core identity razor pages project when TestRunProject.Tests
is placed in the same directory as TestRunProject
(the default scaffolded C# ASP.NET core identity razor pages project).
我在https://github.com/ChristianOConnor/amaranth-minal-testing-example有此代碼的 Github 存儲庫。 上面的代碼來自這個提交: 0d768c4aa181cb4289de4b17f1eac222323ee469
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.