单元测试HttpApplication

时间:2009-07-25 15:44:33

标签: c# asp.net unit-testing moq httpapplication

我有一个派生自HttpApplication的类,它增加了一些额外的功能。我需要对这些功能进行单元测试,这意味着我必须能够创建HttpApplication的新实例,伪造请求并检索响应对象。

我究竟如何对HttpApplication对象进行单元测试?我目前正在使用Moq,但我不知道如何设置所需的模拟对象。

3 个答案:

答案 0 :(得分:10)

不幸的是,这并不是特别容易,因为HttpApplication不容易嘲笑;没有可用于模拟的界面,并且大多数方法都没有标记为虚拟。

我最近遇到了与HttpRequest和HttpWebResponse类似的问题。最后,我采用的解决方案是为我想要使用的方法创建一个直接的“传递”包装器:

public class HttpWebRequestWrapper : IHttpWebRequestWrapper
    {
        private HttpWebRequest httpWebRequest;

        public HttpWebRequestWrapper(Uri url)
        {
            this.httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);
        }

        public Stream GetRequestStream()
        {
            return this.httpWebRequest.GetRequestStream();
        }

        public IHttpWebResponseWrapper GetResponse()
        {
            return new HttpWebResponseWrapper(this.httpWebRequest.GetResponse());
        }

        public Int64 ContentLength
        {
            get { return this.httpWebRequest.ContentLength; }
            set { this.httpWebRequest.ContentLength = value; }
        }

        public string Method 
        {
            get { return this.httpWebRequest.Method; }
            set { this.httpWebRequest.Method = value; }
        }

        public string ContentType
        {
            get { return this.httpWebRequest.ContentType; }
            set { this.httpWebRequest.ContentType = value; }
        }
}

等等

这让我模仿我自己的包装器界面。这不一定是世界上最优雅的东西,而是一种非常有用的方法来模拟框架中一些不那么“可模仿”的部分。

在你匆匆离开并做到这一点之前,值得回顾一下你所得到的,看看是否有更好的测试方法可以避免你必须包装课程。

在HttpWebRequest的情况下,HttpApplication等人经常没有恕我直言。

为了在mock中设置这个包装器(使用上面的HttpWebRequest示例),你可以用Moq做这样的事情:

var mockWebRequest = new Mock<IHttpWebRequestWrapper>();
mockWebRequest.SetupSet<string>(c => c.Method = "POST").Verifiable();
mockWebRequest.SetupSet<string>(c => c.ContentType = "application/x-www-form-urlencoded").Verifiable();
mockWebRequest.SetupSet<int>(c => c.ContentLength = 0).Verifiable();

答案 1 :(得分:2)

IMHO通过扩展HttpApplication来添加功能并不是最好的选择。由于私有/内部/密封类,因此很难模拟HttpContext,即使你成功,你的单元测试也会因为模拟代码而变得混乱,你将无法理解你实际测试的内容。

您能否详细说明您要添加的功能?也许有更好的方法可以将此功能添加到您的应用程序中。

答案 2 :(得分:2)

我之前发现了以下博客,它解释了使用Microsoft Moles的一个很好的方法。

http://maraboustork.co.uk/index.php/2011/03/mocking-httpwebresponse-with-moles/

简而言之,解决方案建议如下:

    [TestMethod]
    [HostType("Moles")]
    [Description("Tests that the default scraper returns the correct result")]
    public void Scrape_KnownUrl_ReturnsExpectedValue()
    {
        var mockedWebResponse = new MHttpWebResponse();

        MHttpWebRequest.AllInstances.GetResponse = (x) =>
        {
            return mockedWebResponse;
        };

        mockedWebResponse.StatusCodeGet = () => { return HttpStatusCode.OK; };
        mockedWebResponse.ResponseUriGet = () => { return new Uri("http://www.google.co.uk/someRedirect.aspx"); };
        mockedWebResponse.ContentTypeGet = () => { return "testHttpResponse"; }; 

        var mockedResponse = "<html> \r\n" +
                             "  <head></head> \r\n" +
                             "  <body> \r\n" +
                             "     <h1>Hello World</h1> \r\n" +
                             "  </body> \r\n" +
                             "</html>";

        var s = new MemoryStream();
        var sw = new StreamWriter(s);

            sw.Write(mockedResponse);
            sw.Flush();

            s.Seek(0, SeekOrigin.Begin);

        mockedWebResponse.GetResponseStream = () => s;

        var scraper = new DefaultScraper();
        var retVal = scraper.Scrape("http://www.google.co.uk");

        Assert.AreEqual(mockedResponse, retVal.Content, "Should have returned the test html response");
        Assert.AreEqual("http://www.google.co.uk/someRedirect.aspx", retVal.FinalUrl, "The finalUrl does not correctly represent the redirection that took place.");
    }