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






4.88/5 (6投票s)
当你编写一个可单元测试的控制器时,为了方便起见,最好避免对 HttpContext 的任何依赖。 如果你在控制器中使用任何会话变量,这将使你的控制器难以测试。
引言
当你编写一个可单元测试的控制器时,为了方便起见,最好避免对 HttpContext
的任何依赖。 如果你在控制器中使用任何会话变量,这将使你的控制器难以测试。 在这里,我尝试提供一个解决方案,这可能有助于解决这种情况。
Using the Code
步骤 1:编写一个接口,IStateProvider
public interface IStateProvider
{
object this[string key] { get; set; }
void Remove(string key);
}
步骤 2:编写一个类,SessionStateProvider
来实现 IStateProvider
。 SessionStateProvider
将使用 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
的依赖,这将简化测试驱动开发。 整个想法是使开发人员能够独立于其他依赖项来开发和测试控制器。
希望对大家有所帮助... 请继续发布你的评论。 :-)