单元测试 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 方法中使用什么参数。

单元测试 ASP.NET(不是 MVC) - 如何通过“请求在此上下文中不可用”

我最近一直在为类似的问题而苦苦挣扎,真正有帮助的是 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(;现在使用参数源中的值    返回更改;}

我希望你明白这个想法并发现这很有用

测试使用 HttpContext

的方法的关键是使用 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,则应查看文档而不是添加单元测试。