单元测试 ASP.NET(不是 MVC) - 如何通过“请求在此上下文中不可用”
本文关键字:上下文 请求 何通过 NET ASP 不是 MVC 单元测试 | 更新日期: 2023-09-27 18:34:11
我仍在尝试为 ASP.NET 站点(不是MVC(添加一些单元测试。 我需要测试的方法之一是使用HttpRequest Request
对象,确切地说Request.Path
。 我正在尝试使用Visual Studio 2008的内置测试框架编写测试。 每当测试执行有问题的方法时,我都会收到System.Web.HttpExecption: Request is not Available in this context
。 我理解为什么它不可用(没有正在运行的 Web 服务器,也没有提供路径(,但是我如何继续测试该方法?
由于每个人都喜欢看代码,以下是有问题的代码:
protected string PageName
{
get
{
return Path.GetFileName(Request.Path).Substring(0, Path.GetFileName(Request.Path).Length - 5);
}
}
protected Change SetupApproval(string changeDescription)
{
Change change = Change.GetInstance();
change.Description = changeDescription;
change.DateOfChange = DateTime.Now;
change.Page = PageName;
return change;
}
这是测试:
[TestMethod]
public void SetupApproval_SubmitChange_ValidateDescription()
{
var page = new DerivedFromInternalAppsBasePage_ForTestingOnly();
var messageToTest = "This is a test description";
var change = page.SetupApproval(messageToTest);
Assert.IsTrue(messageToTest == change.Description);
}
此外,我还在这里阅读了Microsoft的文档:http://msdn.microsoft.com/en-us/library/ms182526(v=vs.90(.aspx并尝试使用他们建议的[HostType("ASP.NET")]
、[UrlToTest(http://localhost:port/pathToAspxPage.aspx")]
和[AspNetDevelopmentServer("C:'PathToDllAssembly", "NotSureParameter")]
属性,但没有运气。 (如您所见,我不确定应该对一些参数使用什么。
最后,我尝试了Phil Haack的TestWebServer http://haacked.com/archive/2006/12/12/Using_WebServer.WebDev_For_Unit_Tests.aspx并通读斯科特·汉塞尔曼的帖子 http://www.hanselman.com/blog/NUnitUnitTestingOfASPNETPagesBaseClassesControlsAndOtherWidgetryUsingCassiniASPNETWebMatrixVisualStudioWebDeveloper.aspx对于 Phil 的服务器,我不确定我将在 ExtractResource
方法中使用什么参数。
我最近一直在为类似的问题而苦苦挣扎,真正有帮助的是 Microsoft Research - http://research.microsoft.com/en-us/projects/moles/的 Moles 框架。它允许你伪造BCL中的任何内容,包括HttpContext.Current。
与你遇到的问题非常相似的问题,在Michael Feathers的"有效地使用遗留代码"一书中描述。 特别是,重构称为"适应参数"。
代码的"问题"在于它直接耦合到HttpRequest,特别是Request.Path。 因此,总体方法是您希望将代码与 HttpRequest 分离。
与上面建议的类似,这是另一种按照Michael Feather书中的想法进行解耦的方法。 我还没有尝试编译这个,所以请原谅任何拼写错误或语法错误。
公共接口参数源{ 公共字符串路径 {get; }}公共类 假参数源 : 参数源{ 公共字符串值; 公共字符串路径 { get { 返回值 } }}公共类 RealParameterSource : ParameterSource{ 私有 HttpRequest 请求; public RealParameterSource(HttpRequest aRequest( { 请求 = a请求; } 公共字符串路径 { get { 返回请求。路径 } }}
现在,这是您需要更改的重要部分(这是一种方法(:
小重命名受保护的字符串 GetPageName(参数源({ 返回 Path.GetFileName(source.路径(。子字符串(0, 路径.获取文件名(源.路径(。长度 - 5(;}
以上注入发生在方法级别。 您也可以通过构造函数或属性来执行此操作。
您的测试代码现在可能如下所示:
受保护的更改设置审批(字符串更改说明({ ParameterSource p = new FakeParameterSource { Value = "mypath" }; 更改更改 = Change.GetInstance((; 改变。描述 = 更改描述; 改变。更改日期 = 日期时间.现在; 改变。页面 = 获取页面名称(p(;现在使用参数源中的值 返回更改;}
我希望你明白这个想法并发现这很有用
的方法的关键是使用 HttpContextBase。HttpContextBase是一个抽象类,它很容易被模拟。不幸的是,HttpContext没有实现HttpContextBase,所以你需要使用HttpContextWrapper将真正的HttpContext包装到HttpContextBase。这篇文章有一个很好的简单解释:http://splinter.com.au/httpcontext-vs-httpcontextbase-vs-httpcontext
您的问题没有说明示例代码的位置。如果这一切都在代码隐藏中,您将很难尝试对其进行测试。您应该研究模型-视图-表示器 (MVP( 模式,而不是在代码隐藏中使用逻辑。MVP 有框架,但自己做也很容易。
在 MVP 演示器中包含所有逻辑和页面代码隐藏仅实现包含可绑定到 UI 的属性的视图接口。所有依赖项都可以注入演示器,使其易于测试。
我同意@Alex Taylor的观点(对不起,我不能发表评论(:对(非MVC(Web应用程序进行单元测试的最佳方法是确保位不依赖于存在的整个环境;这就是为什么它被称为单元测试,毕竟。 所以你可以用这个替换PageName
:
protected string PageName
{
get
{
return GetPageName(Request.Path);
}
}
protected static string GetPageName(string path)
{
return Path.GetFileNameWithoutExtension(path);
}
有了这个,你可以对GetPageName
进行单元测试,并确信PageName按预期工作。
请记住,尝试Request.Path
单元测试是没有意义的,因为它具有它应该履行的预期行为(或"合同"(。 如果您不确定在不同情况下会返回什么 Request.Path,则应查看文档而不是添加单元测试。