C# 在ASP.NET WebApi 2中测试OWIN中间件:如何设置cookie?
我正在尝试在ASP.NET WebApi 2应用程序中测试OWIN中间件组件。中间件应该查看传入请求的cookie,在将请求提交给下一个组件之前修改请求中的一些内容,并可能在发出请求时设置cookie 让我大吃一惊的是,C# 在ASP.NET WebApi 2中测试OWIN中间件:如何设置cookie?,c#,unit-testing,cookies,owin,C#,Unit Testing,Cookies,Owin,我正在尝试在ASP.NET WebApi 2应用程序中测试OWIN中间件组件。中间件应该查看传入请求的cookie,在将请求提交给下一个组件之前修改请求中的一些内容,并可能在发出请求时设置cookie 让我大吃一惊的是,OwinRequest.Cookies属性的类型似乎不允许修改,而属性本身是只读的,这意味着我不能使用RequestCookieCollection(IDictionary)构造函数初始化已经包含Cookies的集合,并在请求时进行设置 我想这样做: var context =
OwinRequest.Cookies
属性的类型似乎不允许修改,而属性本身是只读的,这意味着我不能使用RequestCookieCollection(IDictionary)
构造函数初始化已经包含Cookies的集合,并在请求时进行设置
我想这样做:
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
var context=new OwinContext();
//备选案文1:
context.Request.Cookies.Append(“cookie名称”、“cookie值”);
//备选案文2:
var cookies=newrequestCookieCollection(新字典{{“cookie名称”,“cookie值”});
context.Request.Cookies=Cookies;
等待myMiddleware.Invoke(上下文);
//断言关于context.Response的内容
但由于上述原因,这不起作用
我本来希望不必完全模仿
IOwinContext
,因为将其设置为功能良好的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");
}
}
}
只有必要的依赖关系需要被模拟,测试才能顺利完成,预期的行为才能得到验证
由于请求实现的
Cookies
属性无法被覆盖,因此必须使用抽象。然而,这在模拟所需行为方面提供了更大的灵活性。给出一个示例,说明在执行测试时如何使用上下文。模拟上下文是一件简单的事情,这取决于测试所需的内容。否则,如果您想访问完整的管道,您可以使用TestServer的内存中集成测试。@Nkosi:提供的示例说明了我想做的还不够吗?我的中间件基本上做到了以下几点:1。检查传入请求上是否存在cookie。如果cookie存在,则使用其值设置标头,以便此组件后面的管线认为标头始终存在。2.调用下一个组件。3.在退出时,检查一些条件,并可能设置cookie值。我很好奇中间件是如何定义的,因为它将决定如何创建和使用中间件。我已经计算出了你在OP中包含的流程要点。你最后的评论比我计划展示的示例更清楚,所以我会更新它。最后一个关键点是中间件定义本身。将代码移动到单独的类中通常更容易。单元测试会让你的课程更容易。在这种情况下,您仍然需要检查该中间件是否正确连接。如果您有集成或api测试,那么对您的coockieService和集成测试进行一些单元测试就足够了,该中间件正在按预期工作。我希望我能够避免所有这些模拟仪式;毕竟,除了饼干,我什么都想要有规律的行为。但这可能是不可能的。@Tomasasachan您是否尝试过使用TestServer来查看是否可以在内存集成测试期间访问cookies集合?缺少一个实际运行的服务器,这是我所知道的唯一一个完整框架/管道将发挥作用的场景。我有(很多)其他测试使用TestServer
方法来执行此代码;这个问题是关于在没有完整管道的情况下对这个特定组件进行单元测试。由于该组件应该同时修改传入和传出请求,因此我想验证它是否正确地修改了传入和传出请求,而不必连接其他一些东西。模拟IOwinContext
的所有相关部分都是可行的,但我觉得它把测试与实现联系得太紧密了(即,只有模拟行为可用,因此如果我改变实现目标的方式,我还必须改变模拟设置)。
[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");
}
}