MVC의 Mock HttpContext 테스트

7477 단어 context
웹에서 테스트 드라이브를 개발하는 데 있어서 비교적 큰 어려움은 아날로그 HttpContext이다. 이것은 너무 복잡하다.
moq 프레임워크는 강력한 시뮬레이션 능력을 제공하지만, HttpContext 대상을 시뮬레이션하려면 스스로 해야 한다.
이를 위해, 나는 스스로 방법을 써서 이 일을 완성했다.그 중에서도 Log4Net을 사용하여 작업 상황을 출력합니다.
/// <summary>
///   
///  
///     Request  
///         AppRelativeCurrentExecutionFilePath,
///         ApplicationPath
///         PathInfo
///     Response  
///         ApplyAppPathModifier
/// </summary>
/// <returns></returns>
private Moq.Mock<System.Web.HttpContextBase> CreateHttpContext()
{
    log4net.ILog log = log4net.LogManager.GetLogger("CreateHttpContext");

    string ApplicationPath = "/";
    string PathInfo = "";
    string AppRelativeCurrentExecutionFilePath = "~/";

    var contextMock = new Moq.Mock<System.Web.HttpContextBase>();

    contextMock
        .Setup(c => c.Request.AppRelativeCurrentExecutionFilePath)
        .Returns(AppRelativeCurrentExecutionFilePath)
        .Callback(() => log.Info("Calling AppRelativeCurrentExecutionFilePath"));

    contextMock
        .Setup(c => c.Request.ApplicationPath)
        .Returns(ApplicationPath)
        .Callback(() => log.Info("Calling ApplicationPath"));
    contextMock.Setup(rc => rc.Request.PathInfo)
        .Returns(PathInfo)
        .Callback(() => log.Info("Calling PathInfo"));

    contextMock
        .Setup(rc => rc.Response.ApplyAppPathModifier(Moq.It.IsAny<string>()))
        .Returns((string s) => s)
        .Callback((string s) => log.InfoFormat("Calling ApplyAppPathModifier: {0}.", s));

    return contextMock;
}

이 방법은 이미 내가 필요로 하는 테스트를 완성할 수 있지만, 나는 그것을 추출하여 더욱 통용되는 Mock 방법을 얻을 수 있기를 바란다.
곧 나는 이 일이 이미 아주 오래 전에 Scott Hanselman에 한 번 소개되었는데, 그 중에서 심지어 서로 다른 Mock 프레임워크 아래의 제공 방법까지 썼다는 것을 발견했다.그러나 moq버전의 작가는 그가 아니라 다른 사람이다. Daniel Cazzulino. 이 글은 여기서 찾을 수 있다. http://www.hanselman.com/blog/ASPNETMVCSessionAtMix08TDDAndMvcMockHelpers.aspx, 그리고 Daniel Cazzulino의 블로그도 볼 수 있다. http://blogs.clariusconsulting.net/kzu/
그러나 그의 문장은 2008년에 쓴 것으로 정말 너무 낡았다.당시에는 MVC의 Preview2였는데, moq는 그때 이미 탄생했다. 내가 너무 과문한 것 같다.
우리의 주제로 돌아가서 이렇게 오랜 시간이 지나서 moq는 이미 약간의 변화가 생겼다. 최신의 moq 문법 수정을 사용한 후에 그의 코드가 테스트를 통과하지 못한 것을 발견했다.
나와 비교해 보니 Response에서 Apply App Path Modifier 방법에 대한 지원이 줄어들었고 증가한 후에 정상이 되었다.
다음은 수정된 코드입니다. 편의를 제공해 주십시오.
using System;
using System.Web;
using System.Text.RegularExpressions;
using System.IO;
using System.Collections.Specialized;
using System.Web.Mvc;
using System.Web.Routing;

using Moq;

namespace UnitTests
{
    public static class MvcMockHelpers
    {
        public static HttpContextBase FakeHttpContext()
        {
            var context = new Mock<HttpContextBase>();
            var request = new Mock<HttpRequestBase>();
            var response = new Mock<HttpResponseBase>();
            var session = new Mock<HttpSessionStateBase>();
            var server = new Mock<HttpServerUtilityBase>();

            //   Response   ApplyAppPathModifier  
            response
                .Setup(rsp => rsp.ApplyAppPathModifier(Moq.It.IsAny<string>()))
                .Returns((string s) => s);
                
            context.Setup(ctx => ctx.Request).Returns(request.Object);
            context.Setup(ctx => ctx.Response).Returns(response.Object);
            context.Setup(ctx => ctx.Session).Returns(session.Object);
            context.Setup(ctx => ctx.Server).Returns(server.Object);

            return context.Object;
        }

        public static HttpContextBase FakeHttpContext(string url)
        {
            HttpContextBase context = FakeHttpContext();
            context.Request.SetupRequestUrl(url);
            return context;
        }

        // Controller  
        public static void SetFakeControllerContext(this Controller controller)
        {
            var httpContext = FakeHttpContext();
            ControllerContext context = new ControllerContext(new RequestContext(httpContext, new RouteData()), controller);
            controller.ControllerContext = context;
        }

        static string GetUrlFileName(string url)
        {
            if (url.Contains("?"))
                return url.Substring(0, url.IndexOf("?"));
            else
                return url;
        }

        static NameValueCollection GetQueryStringParameters(string url)
        {
            if (url.Contains("?"))
            {
                NameValueCollection parameters = new NameValueCollection();

                string[] parts = url.Split("?".ToCharArray());
                string[] keys = parts[1].Split("&".ToCharArray());

                foreach (string key in keys)
                {
                    string[] part = key.Split("=".ToCharArray());
                    parameters.Add(part[0], part[1]);
                }

                return parameters;
            }
            else
            {
                return null;
            }
        }

        //   HttpRequestBase
        public static void SetHttpMethodResult(this HttpRequestBase request, string httpMethod)
        {
            Mock.Get(request)
                .Setup(req => req.HttpMethod)
                .Returns(httpMethod);
        }

        //  
        public static void SetupRequestUrl(this HttpRequestBase request, string url)
        {
            log4net.ILog log = log4net.LogManager.GetLogger("CreateHttpContext");

            if (url == null)
                throw new ArgumentNullException("url");

            if (!url.StartsWith("~/"))
                throw new ArgumentException("Sorry, we expect a virtual url starting with \"~/\".");

            var mock = Mock.Get(request);

            mock.Setup(req => req.QueryString)
                .Returns(GetQueryStringParameters(url));
            mock.Setup(req => req.AppRelativeCurrentExecutionFilePath)
                .Returns(GetUrlFileName(url))
                .Callback(() => log.Info("Calling AppRelativeCurrentExecutionFilePath"));


            mock.Setup(req => req.PathInfo)
                .Returns(string.Empty);

        }
 
    }
}

좋은 웹페이지 즐겨찾기