65.9K
CodeProject 正在变化。 阅读更多。
Home

MVC 测试驱动开发:会话变量

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (6投票s)

2011年8月12日

CPOL

2分钟阅读

viewsIcon

52430

当你编写一个可单元测试的控制器时,为了方便起见,最好避免对 HttpContext 的任何依赖。 如果你在控制器中使用任何会话变量,这将使你的控制器难以测试。

引言

当你编写一个可单元测试的控制器时,为了方便起见,最好避免对 HttpContext 的任何依赖。 如果你在控制器中使用任何会话变量,这将使你的控制器难以测试。 在这里,我尝试提供一个解决方案,这可能有助于解决这种情况。

Using the Code

步骤 1:编写一个接口,IStateProvider

public interface IStateProvider
{
    object this[string key] { get; set; }
    void Remove(string key);
}

步骤 2:编写一个类,SessionStateProvider 来实现 IStateProviderSessionStateProvider 将使用 Session 来存储变量。

public class SessionStateProvider : IStateProvider
{
    public object this[string key]{
        get
        {
            return HttpContext.Current.Session[key];
        }
        set
        {
            HttpContext.Current.Session[key] = value;
        }
    }

    public void Remove(string key)
    {
        HttpContext.Current.Session.Remove(key);
    }
}

步骤 3:为你的所有控制器编写一个基类,例如 BaseController ,并在其中公开一个属性,例如 CSession 。 你可以看到该属性最初未设置。

public class BaseController : Controller
{
    public IStateProvider CSession
    {
        get;
        set;
    }
}

步骤 4:编写一个自定义控制器工厂,我们将在其中将状态提供程序设置为会话状态提供程序。 你也可以在此处注入其他依赖项(如果有)。

public class MyControllerFactory:DefaultControllerFactory
{
    public override IController CreateController
    (System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        IController controller;
        controller = base.CreateController(requestContext, controllerName) ;

        //Inject the Dependency.
        if (controller is BaseController)
        {
            var baseController = (BaseController)controller;
            baseController.CSession = new SessionStateProvider();

        }
        return controller;
    }
}

步骤 5:在你的 Global.asax.cs 文件中注册你的 控制器工厂

void Application_Start(object sender, EventArgs e)
{
    ControllerBuilder.Current.SetControllerFactory
        (new Fadt.CMS.Web.Core.CMSControllerFactory());
    RegisterRoutes(RouteTable.Routes);
}

步骤 6:从 BaseController 扩展你的所有控制器。 现在,你可以使用 CSession 代替 Session。 由于 控制器工厂 已将 SessionStateProvider 注入到 CSession 属性中,因此你设置到 CSession 的所有值都将存储在 Session 中。

public class MyController : BaseController
{
    public MyController()
    {
        CSession["MY_VAR"] = obj;
        CSession.Remove(“MY_VAR”);
    }

测试控制器

在测试项目中,编写另一个 IStateProvider 的实现。 此实现会将变量保存到 字典 中,而不是 Session 中。 因此,通过控制器注入依赖项,我们已将控制器与 HttpContext 解耦。

public class DictionaryStateProvider:IStateProvider
{
    private Dictionary<string,object> stateValueCollection =
        new Dictionary<string,object>();
    public object this[string key]
    {
        get
        {
            if (stateValueCollection.ContainsKey(key))
                return stateValueCollection[key];
            else
                return null;
        }
        set
        {
            stateValueCollection[key] = value;
        }
    }

    public void Remove(string key)
    {
        stateValueCollection.Remove(key);
    }
}

现在,在测试方法中,编写一个初始化方法来初始化控制器以进行测试。

public static void InitializeController(BaseController controller)
{
    controller.CSession = new DictionaryStateProvider();
    //You can do some other injections as well here
}

[TestMethod]
public void Is_Index_Data_Loaded_Properly()
{
   MyController controller = new MyController();
   InitializeController(controller);
   controller.Index() //Call the method to test
   Assert.IsTrue(true);
}

关注点

在这里,我们避免了控制器对 HttpContext 的依赖,这将简化测试驱动开发。 整个想法是使开发人员能够独立于其他依赖项来开发和测试控制器。

希望对大家有所帮助... 请继续发布你的评论。 :-)

© . All rights reserved.