C#学习教程:模拟HttpContext.Current.Request中的ServerVariables服务器变量["MY_CUSTOM_VAR"];我尝试过的是模拟那些对象并插入我自己的变量/集合并检查几种情况(例如变量丢失,值为空......)我能够创建HttpContext,HttpRequest,HttpResponse实例并分配它们但是它们中的每一个都只是一个没有接口或虚拟属性的普通类,ServerVariables的初始化发生在某个地方。HttpContext模拟:varhttpRequest=newHttpRequest("","http://excaple.com/","");varstringWriter=newStringWriter();varhttpResponse=newHttpResponse(stringWriter);varhttpContextMock=newHttpContext(httpRequest,httpResponse);HttpContext.Current=httpContextMock;尝试#1通过反射调用私有方法varserverVariables=HttpContext.Current.Request.ServerVariables;varserverVariablesType=serverVariables.GetType();MethodInfoaddStaticMethod=serverVariablesType.GetMethod("AddStatic"BindingFlags.Instance|BindingFlags.FlattenHierarchy|BindingFlags.NonPublic);addStaticMethod.Invoke(serverVariables,newobject[]{"MY_CUSTOM_VAR","value"});失败,错误说明集合是只读的。尝试#2用我自己的实例替换ServerVariablesvarrequest=HttpContext.Current.Request;varrequestType=request.GetType();varvariables=requestType.GetField("_serverVariables",BindingFlags.Instance|BindingFlags.NonPublic);变量。SetValue(请求,新的NameValueCollection{{“MY_CUSTOM_VAR”,“值”}});失败,因为无法将NameValueCollection转换为HttpServerVarsCollection。那是因为HttpServerVarsCollection实际上是一个内部类,所以我不能创建它的实例或强制转换它。所以问题是——我如何模拟ServerVariables或在那里插入值?谢谢我在http://forums.asp.net/t/1125149.aspx找到了答案无法访问存储服务器变量的对象。但是可以使用反射访问它。因此,使用反射我们可以设置我们想要的值。以下扩展方法将有助于设置任何服务器变量。publicstaticvoidAddServerVariable(thisHttpRequestrequest,stringkey,stringvalue){BindingFlagstemp=BindingFlags.NonPublic|BindingFlags.实例|BindingFlags.Static;方法信息addStatic=null;.ServerVariables.GetType();MethodInfo[]方法=type.GetMethods(temp);foreach(方法中的MethodInfo方法){switch(method.Name){case"MakeReadWrite":makeReadWrite=method;休息;案例“MakeReadOnly”:makeReadOnly=方法;休息;case"AddStatic":addStatic=方法;休息;}}makeReadWrite.Invoke(request.ServerVariables,null);string[]values={key,value};addStatic.Invoke(request.ServerVariables,值);makeReadOnly.Invoke(request.ServerVariables,null);问题是,HttpContext和HttpRequest对象是不可模拟的。HttpContext这是复古的asp.net上下文。这样做的问题是它没有基类并且不是虚拟的,所以它不能用于测试(不能模拟它)。建议不要将其作为函数参数传递,而是传递一个HttpContextBase类型的变量。HttpContextBase这是HttpContext的(新的c#3.5)替代品。因为它是抽象的,所以现在是可以模仿的。这个想法是,您希望通过上下文传递的函数应该接收其中之一。它是由HttpContextWrapper具体实现的HttpContextWrapper在C#3.5中也是新的——这是HttpContextBase的具体实现。要在普通网页中创建其中一个,请使用newHttpContextWrapper(HttpContext.Current)。这个想法是,为了使您的代码单元可测试,您将所有变量和函数参数声明为HttpContextBase类型,并使用CastleWindsor等IOC框架来注入它。在正常代码中,castle将注入“newHttpContextWrapper(HttpContext.Current)”的等效项,而在测试代码中,您将获得HttpContextBase的模拟。(来源:http://www.splinter.com.au/httpcontext-vs-httpcontextbase-vs-httpcontext/)你需要像这样用HttpContextBase包装它:varresult=YourMethod(newHttpContextWrapper(HttpContext.Current));然后,当您为YourMethod(HttpContextBasecontext)编写测试时,您可以使用Moq轻松模拟HttpContextBase:varrequest=newMock(MockBehavior.Strict);request.Setup(x=>x.ServerVariables).Returns(newSystem.Collections.Specialized.NameValueCollection{{"MY_CUSTOM_VAR","你的值在这里"}});varcontext=newMock();context.SetupGet(x=>x.Request).Returns(request.Object);然后你可以使用context.Object来调用你的HttpContext对象;这正是您应该重构代码的情况。重构代码示例:publicclassMyService{publicServiceResultSomeMethod(){...varvalue=GetVariable(System.Web.HttpContext.Current,"somevarname");...}protectedvirtualstringGetVariable(HttpContextfromContext,stringname){returnfromContext.Request.ServerVariables[name];在你的测试中:classMyTestableService:MyService{}publicDictionaryMockedVariables{get;放;}}[测试]publicvoidTestSomeMethod(){varserviceUnderTest=newMyTestableService{MockedVariables=newDictionary{{"somevarname","varvalue"}}};//更多的安排在这里Assert.AreEqual(expectedResult,serviceUnderTest.SomeMethod());}当然,你可以将方法完全抽离成一个单独的依赖。以上就是C#学习教程:模拟HttpContext.Current.Request中ServerVariables共享的所有内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
