如何使用 ASP.NET 5 (MVC 6) 中的响应属性对控制器操作进行单元测试
本文关键字:属性 响应 控制器 操作 单元测试 NET ASP 何使用 MVC | 更新日期: 2023-09-27 18:34:12
在 ASP.NET Core 1.0(MVC 6(项目中,我有一个控制器操作方法,其中我使用Response
属性来设置标头:
[HttpGet]
public IActionResult Get()
{
...
Response.Headers.Add("Location", location);
...
}
我尝试为此操作方法实现单元测试,但 Response
属性的值为 null。
这在以前版本的 ASP.NET 中很容易解决,因为 Response
属性有一个 setter,您可以在单元测试期间将其值设置为新的 HttpResponse
实例。
但是在 ASP.NET 5中,Response
没有二传手,只有一个getter。
如何在单元测试中设置Response
值?
更新:只是为了澄清:这个问题是关于 ASP.NET Core 1.0的。作为重复链接的另一个问题是关于 ASP.NET 4,从那时起 API 发生了变化,因此那里的答案不适用于这个问题。
我找到了解决问题的一种解决方案,但是,它有点乏味和复杂,所以我仍然有兴趣看到一种更简单的方法,如果有的话。
Controller
从 ActionContext.HttpContext
获取其Response
属性的值。使模拟变得困难的是,所有这些属性都是只读的,所以我们不能简单地设置一个模拟值,我们必须为每个游戏对象创建模拟。
我在测试中需要的响应部分是Headers
集合,因此我必须创建和使用以下模拟来使其可用。(模拟是用最小起订量完成的。
var sut = new MyController();
// The HeaderDictionary is needed for adding HTTP headers to the response.
// This needs a couple of different Mocks, because many properties in the class model are read-only.
var headerDictionary = new HeaderDictionary();
var response = new Mock<HttpResponse>();
response.SetupGet(r => r.Headers).Returns(headerDictionary);
var httpContext = new Mock<HttpContext>();
httpContext.SetupGet(a => a.Response).Returns(response.Object);
sut.ActionContext = new ActionContext()
{
HttpContext = httpContext.Object
};
这比我希望看到的模拟单个属性的代码要多一些,但是我还找不到更好的方法,而且它似乎运行良好。
您可以使用具有虚拟属性的 ResponseWrapper,您可以模拟它并期望使用"Location"参数调用虚拟 AddHeader 方法。相关问题这里: MOQ - 模拟 MVC 控制器的响应.Cookies.Clear((
您可以查看这些示例:对于 ASP.Net 5 MVC 6:
- http://www.jerriepelser.com/blog/unit-testing-controllers-aspnet5
- http://dotnetthoughts.net/creating-unit-tests-for-asp-net-mvc-6-applications/
如果你想尝试NancyFx(http://nancyfx.org/((https://github.com/NancyFx/Nancy(,另一种选择很容易:https://github.com/NancyFx/Nancy/wiki/Testing-your-application
例如 - 如果您正在测试登录页面并想要验证 如果用户输入,则用户被重定向到"错误"页面 您可能使用应该重定向到的错误凭据 断言:
[Fact] public void Should_redirect_to_login_with_error_details_incorrect() { // Given var bootstrapper = new DefaultNancyBootstrapper(); var browser = new Browser(bootstrapper); // When var response = browser.Post("/login/", (with) => { with.HttpRequest(); with.FormValue("Username", "username"); with.FormValue("Password", "wrongpassword"); }); // Then response.ShouldHaveRedirectedTo("/login?error=true&username=username");
}
还有更多:
[Fact] public void Should_display_error_message_when_error_passed() { // Given var bootstrapper = new DefaultNancyBootstrapper(); var browser = new Browser(bootstrapper); // When var response = browser.Get("/login", (with) => { with.HttpRequest(); with.Query("error", "true"); }); // Then response.Body["#errorBox"] .ShouldExistOnce() .And.ShouldBeOfClass("floatingError") .And.ShouldContain( "invalid", StringComparison.InvariantCultureIgnoreCase); }