如何使用 ASP.NET 5 (MVC 6) 中的响应 属性 对控制器操作进行单元测试?
How to unit test a Controller action using the Response property in ASP.NET 5 (MVC 6)?
在 ASP.NET Core 1.0 (MVC 6) 项目中,我有一个控制器操作方法,我在其中使用 Response
属性设置 header:
[HttpGet]
public IActionResult Get()
{
...
Response.Headers.Add("Location", location);
...
}
我试图为此操作方法实施单元测试,但是 Response
属性 的值为 null。
这在以前的ASP.NET版本中很容易解决,因为Response
属性有一个setter,你可以简单地将它的值设置为a单元测试期间的新 HttpResponse
个实例。
但是在ASP.NET5中Response
没有一个setter,只有一个getter.
如何在单元测试中设置 Response
的值?
更新:澄清一下:这个问题是关于ASP.NET Core 1.0的。另一个链接为重复的问题是关于 ASP.NET 4,Api 从那时起发生了变化,因此那里的答案不适用于这个问题。
您可以使用具有虚拟属性的 ResponseWrapper,您可以模拟它并期望一次调用带有 "Location" 参数的虚拟 AddHeader 方法。
相关问题这里:MOQ - Mocking MVC Controller's Response.Cookies.Clear()
您可以查看这些示例:for 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) it's quite easy: https://github.com/NancyFx/Nancy/wiki/Testing-your-application
For example - if you were testing a login page and wanted to verify
that the user was redirected to an “error” page if they entered
incorrect credentials you could use the ShouldHaveRedirectedTo
assertion:
[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);
}
我找到了一个解决问题的方法,但是,它有点乏味和复杂,所以我仍然有兴趣看到一种更简单的方法,如果存在的话。
Controller
从 ActionContext.HttpContext
获取其 Response
属性 的值。让模拟变得如此困难的是所有这些属性都是只读的,所以我们不能简单地设置模拟值,我们必须为每个正在运行的对象创建模拟。
我在测试中需要的响应部分是 Headers
集合,因此我必须创建并使用以下模拟来使其可用。 (模拟是用 Moq 完成的。)
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
};
这比我想看到的模拟单个 属性 的代码要多一些,但我还找不到更好的方法,而且它似乎工作得很好。
在 ASP.NET Core 1.0 (MVC 6) 项目中,我有一个控制器操作方法,我在其中使用 Response
属性设置 header:
[HttpGet]
public IActionResult Get()
{
...
Response.Headers.Add("Location", location);
...
}
我试图为此操作方法实施单元测试,但是 Response
属性 的值为 null。
这在以前的ASP.NET版本中很容易解决,因为Response
属性有一个setter,你可以简单地将它的值设置为a单元测试期间的新 HttpResponse
个实例。
但是在ASP.NET5中Response
没有一个setter,只有一个getter.
如何在单元测试中设置 Response
的值?
更新:澄清一下:这个问题是关于ASP.NET Core 1.0的。另一个链接为重复的问题是关于 ASP.NET 4,Api 从那时起发生了变化,因此那里的答案不适用于这个问题。
您可以使用具有虚拟属性的 ResponseWrapper,您可以模拟它并期望一次调用带有 "Location" 参数的虚拟 AddHeader 方法。 相关问题这里:MOQ - Mocking MVC Controller's Response.Cookies.Clear()
您可以查看这些示例:for 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) it's quite easy: https://github.com/NancyFx/Nancy/wiki/Testing-your-application
For example - if you were testing a login page and wanted to verify that the user was redirected to an “error” page if they entered incorrect credentials you could use the ShouldHaveRedirectedTo assertion:
[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); }
我找到了一个解决问题的方法,但是,它有点乏味和复杂,所以我仍然有兴趣看到一种更简单的方法,如果存在的话。
Controller
从 ActionContext.HttpContext
获取其 Response
属性 的值。让模拟变得如此困难的是所有这些属性都是只读的,所以我们不能简单地设置模拟值,我们必须为每个正在运行的对象创建模拟。
我在测试中需要的响应部分是 Headers
集合,因此我必须创建并使用以下模拟来使其可用。 (模拟是用 Moq 完成的。)
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
};
这比我想看到的模拟单个 属性 的代码要多一些,但我还找不到更好的方法,而且它似乎工作得很好。