代码之家  ›  专栏  ›  技术社区  ›  Geo

如何解决测试中的基础控制器依赖注入问题?

  •  6
  • Geo  · 技术社区  · 15 年前

    为了能够构造测试用例,我使用依赖注入模式实现了我的MVC基控制器DefaultController。下面的例子:

    public class DefaultController : Controller
    {
        protected readonly ISessionHelper _sessionHelper;
        string _thisUserOpenID;
        protected IUsersRepository _UserRepository;
     ... 
        public DefaultController()
        { } //not for testing
    
        public DefaultController(ISessionHelper session, IUserRepository repo)
        {
           _sessionHelper=session;
           _UserRepository = repo;
         }
     }
    

    然后我让我的控制器使用这个控制器、主控制器、用户控制器等。

    现在,构建一些测试用例时,我发现自己处于一种不知道如何实际使用注入依赖模式的情况。

        [TestMethod]
        public void Welcome_Message_In_ViewData_Has_Coockie_User_Display_Name()
        {
            // Below I want to insert FakeRepositories using 
            //ISessionHelper and so on. but the constructor 
            //for homecontroller don't have it.
            HomeController controller = new HomeController(); 
    

    有什么想法吗?

    2 回复  |  直到 15 年前
        1
  •  5
  •   womp    15 年前

    您的主控制器需要有一个匹配的“可注入”构造函数,然后该构造函数将调用基本构造函数。

    public HomeController(ISessionHelper session, IUserRepository repo)
      : base(session, repo)
        {
    
        }
    

    现在,在测试中,您将使用该构造函数创建家庭控制器,并传递一个模拟会话和用户存储库。说到嘲弄,你可能也对 Scott Hanselman's MvcMockHelpers classes 以及许多流行的模拟框架的代码。

        2
  •  3
  •   Bealer    15 年前

    我不明白为什么你有两个构造器。您应该只有一个,去掉不带参数的构造函数。使用像Castle Windsor这样的DI框架,或者我的首选框架,Autopac将为您处理所有这些问题。然后,就测试而言,使用像moq这样的东西。工业工程

    public DefaultController(ISessionHelper session, IUserRepository repo)
    {
       _sessionHelper = session;
       _UserRepository = repo;
    }
    

    在DI框架中注册defaultcontroller、isessionhelper和iuserrepository。沿着这条线的东西:

    Register(new DefaultController()); (it is something like that in Autofac)
    Register<SessionHelper>().As<ISessionHelper>();
    Register<UserRepository>().As<IUserRepository>();
    

    这样,您就可以从容器中提取defaultcontroller,DI框架将为您注入这两个参数。我总结了一个静态方法来访问我的DI容器,它看起来像:

    var controller = IoC.Resolve<DefaultController>();
    

    基本上去自动对焦看看。还有一个为您注册控制器的Web模块。

    然后对于测试,只需使用moq,或者找到某种形式的“automocker”(谷歌IT)。我会这样做:

    var session = new Mock<ISessionHelper>();
    var repo = new Mock<IUserRepository>();
    repo.Setup(s => s.FindById(123)).Returns(new User());
    
    var conroller = new DefaultController(session.Object, repo.Object);
    controller.Execute();
    

    还有EWWW存储库。有.NET和泛型等…只需为自己创造一个美好的职业。

    var session = IoC.Resolve<ISession>();
    var user1 = session.Get<User>(123);
    var user2 = session.Get<User>(u => u.Username == "admin");
    session.Update(user3);
    

    意味着你只需要传递一件事,你可以用它做任何事情。而不是有时不得不在许多存储库中传递。还可以很好地设置工作单元模式。