mvc.net 实现对Controller层的单元测试

最近有个项目求助,由于开发人员把页面处理的相关逻辑写到了Controller层里,需要增加对Controller层的单元测试。

我看了下Controller层里难于测试的原因主要是httpcontext类难模拟。Controller层用到了session,request信息。

我的解决方法是,在httpcontext与Controller之间增加一个IHttpContextRepository接口,它负责将httpcontext里的内容封装到model里传给Controller。

那么Controller层只和Model层打交道。

定义IHttpContextRepository接口

    public interface IHttpContextRepository
    {
        LogOnModel GetLogOnModel(HttpContextBase context);
        string GetAgent(HttpContextBase context);
    }

定义BaseController,所有的业务Controller派生于BaseController,BaseController内有一个依赖属性IHttpContextRepository。

    public class BaseController : Controller
    {
        protected IHttpContextRepository httpContextRepository;

        public BaseController(IHttpContextRepository prepareControllerVar)
        {
            httpContextRepository = prepareControllerVar;
        }
    }

IHttpContextRepository由依赖注入实现,为此引入了Autofac模块。

在Global.asax中,添加注册组件的代码。

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

            // Setup AutoFac
            var builder = new ContainerBuilder();
            DependancySetup(builder);
            var container = builder.Build();

            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
            
        }

        protected void DependancySetup(ContainerBuilder builder)
        {
            // Controllers
            builder.RegisterControllers(typeof(MvcApplication).Assembly);

            builder.RegisterType<HttpContextRepository>().AsImplementedInterfaces();
        }

添加实现类

    public class HttpContextRepository : IHttpContextRepository
    {
        public LogOnModel GetLogOnModel(HttpContextBase context)
        {
            LogOnModel LGmodel = new LogOnModel();
            LGmodel.UserName = (string)context.Session["NAME"];
            LGmodel.Password = (string)context.Session["PASSWORD"];
            return LGmodel;
        }

        public string GetAgent(HttpContextBase context)
        {
            return context.Request.UserAgent;
        }
    }

在Controller层调用IHttpContextRepository,获取model对象

        [HttpGet]
        public ActionResult Top()
        {
	   ...
            LogOnModel LGmodel = httpContextRepository.GetLogOnModel(this.HttpContext);

            ...

            return View(LGmodel); 
        }

至此,原代码改造完毕。下面要写测试代码。

为了方便Mock,引入Moq模块。

使用了Xunit框架

        public void TopTest_001()
        {
            var mockRepository = new Mock<IHttpContextRepository>();

            LogOnModel model = new Models.LogOnModel { UserName = "tom", Password = "12345678" };
            //单元测试时,我并不关心HttpContext内的内容,所以放个空的object。我关心的是返回的model
            mockRepository.Setup(cr => cr.GetLogOnModel(new object() as HttpContextBase)).Returns(model);
            mockRepository.Setup(cr => cr.GetPhoneFlg(new object() as HttpContextBase)).Returns("IE");

            var controller = new AccountController(mockRepository.Object);

            var result = controller.Top() as ViewResult;
            Assert.Equal("tom", ((LogOnModel)result.ViewData.Model).UserName);
            Assert.Equal("12345678", ((LogOnModel)result.ViewData.Model).Password);
            
        }



你可能感兴趣的:(String,object,单元测试,application,Class,interface)