我正在尝试在 ASP.NET WebApi 2 应用程序中测试 OWIN 中间件组件。中间件应该查看传入请求的 cookie,在将请求传递给下一个组件之前修改请求中的一些内容,并可能在输出时设置 cookie。
让我感到困惑的是 OwinRequest.Cookies
属性类型为 RequestCookieCollection
,这似乎不允许修改,并且属性本身是只读的,这意味着我不能使用 RequestCookieCollection(IDictionary<string,string>)
构造函数来初始化一个已经包含 cookie 的集合,并根据请求进行设置。
我想做这样的事情:
var context = new OwinContext();
// option 1:
context.Request.Cookies.Append("cookie-name", "cookie-value");
// option 2:
var cookies = new RequestCookieCollection(new Dictionary<string, string>{ { "cookie-name", "cookie-value" } });
context.Request.Cookies = cookies;
await myMiddleware.Invoke(context);
// Assert stuff about context.Response
但由于上述原因,这不起作用。
我曾希望不必 mock IOwinContext
entierly,因为用功能良好的 Request
设置它非常方便和 Response
对象(除其他外,我需要在我的实现中查看 Request.User.Identity.IsAuthenticated
)。
最佳答案
以下面为主体的示例中间件进行单元测试
using RequestDelegate = Func<IOwinContext, Task>;
class MyMiddleware {
private readonly RequestDelegate next;
public MyMiddleware(RequestDelegate next) {
this.next = next;
}
public async Task Invoke(IOwinContext context) {
//The middleware is supposed to look at the cookies of the incoming request,
var request = context.Request;
var authenticated = request.User.Identity.IsAuthenticated;
var cookies = request.Cookies;
if (cookies["cookie-name"] != null) {
// 1. check for existence of a cookie on the incoming request.
//if the cookie exists, use its value to set a header,
//so that the pipline after this component thinks the header was always present.
request.Headers.Append("header-name", "header-value");
}
//2. call the next component.
await next.Invoke(context);
//3. on the way out, check for some conditions, and possibly set a cookie value.
if (authenticated) {
context.Response.Cookies.Append("cookie-name", "cookie-value");
}
}
}
并使用提供的有关所需行为的详细信息,
很难使用完整 OwinContext
所需的所有管道对 Controller 进行单元测试。
您已经说明了很多关于访问某些成员的限制。
然而,Owin 提供了许多抽象,允许为孤立的单元测试模拟/ stub /伪造所需的行为。
以下示例基于上面提供的主题,并使用 Moq
模拟框架以及具体实现来正确设置和执行主题中间件的隔离单元测试。
[TestClass]
public class OwinMiddlewareCookiesTest {
[Test]
public async Task MyMiddleware_Should_Set_RequestHeader_And_ResponseHeader() {
//Arrange
var cookieStore = new Dictionary<string, string> { { "cookie-name", "cookie-value" } };
var cookies = new RequestCookieCollection(cookieStore);
var request = Mock.Of<IOwinRequest>();
var requestMock = Mock.Get(request);
requestMock.Setup(_ => _.Cookies).Returns(cookies);
requestMock.Setup(_ => _.User.Identity.IsAuthenticated).Returns(true);
requestMock.Setup(_ => _.Headers.Append(It.IsAny<string>(), It.IsAny<string>()));
var response = new OwinResponse();
var context = Mock.Of<OwinContext>();
var contextMock = Mock.Get(context);
contextMock.CallBase = true;
contextMock.Setup(_ => _.Request).Returns(request);
contextMock.Setup(_ => _.Response).Returns(response);
RequestDelegate next = _ => Task.FromResult((object)null);
var myMiddleware = new MyMiddleware(next);
//Act
await myMiddleware.Invoke(context);
//Assert
requestMock.Verify(_ => _.Headers.Append("header-name", "header-value"));
response.Headers.ContainsKey("Set-Cookie");
}
}
只有必要的依赖项需要被模拟,测试才能完成并验证预期的行为。
并且由于无法覆盖请求实现的 Cookies
属性,因此必须使用抽象。然而,这在模拟所需行为方面提供了更大的灵 active 。
关于c# - 在 ASP.NET WebApi 2 : How to set cookies? 中测试 OWIN 中间件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53099586/