具有多个层的MVC4 TDD

时间:2012-10-20 15:10:34

标签: asp.net-mvc asp.net-mvc-4 tdd unity-container moq

我正在学习DI,IoC和MOQ,所以我可以TDD我的新MVC4应用程序。

我在网上关注了很多例子,但有一件事我无法理解。

我的应用程序由3层(物理项目)组成:

  1. 应用层(控制器/型号/标准MVC4东西)。
  2. 业务层(完成所有计算和处理数据)。
  3. DAL(EF5)。
  4. 现在我有一个非常简单的UserController

    public class UserController : Controller
    {
        readonly IUserRepository _repository;
    
        public UserController(IUserRepository rep)
        {
            _repository = rep;
        }
    
        public ActionResult Index()
        {
            IList<User> users = _repository.Get(10);
            return View(users);
        }
    

    使用Unity注入依赖关系,这很好。

    在业务层中,我有存储库:

    public interface IUserRepository
    {
        IList<User> Get(Int32 count);
    }
    
    public class UserRepository : IUserRepository
    {
        public IList<User> Get(Int32 count)
        {
            // Here I fetch the data from the Database
            // and do some stuff with it, this can be
            // quite a big method.
        }
    }
    

    现在我需要访问我的DAL,我可以在UserRepository的Get方法中执行此操作。

    我该如何对此进行单元测试?由于可测试性,我认为在课堂上不应该存在依赖性。

    如果我在单元测试中使用实际的UserRepository类进行测试,它将转到DAL并使用那里的数据,但我需要模拟数据。

    我是否需要创建另一个IUserDataRepository,从数据库中提取实际数据并将其传递到UserRepository构造函数中,或者我应该使用Unity来处理这个问题?

    可能的答案?

    我创建了一个名为Users的新界面:

    public class Users: IUsers
    {
        private readonly IUserRepository _userRepository;
        public Users(IUserRepository userRepository)
        {
            _userRepository = userRepository;
        }
    
        public User Get(String id)
        {
           // Do all the magic here here
        }
    }
    

    从此界面IUsers

    public interface IUsers
    {
        User Get(String id);
    }
    

    但是我将面向数据库的存储库移到了DAL:

    public class UserRepository : IUserRepository
    { 
        public User Get(String id)
        {
            // Retrieve the user from the database with EF5
        }
    }
    
    public interface IUserRepository
    {
        User Get(String id);
    }
    

    控制器保持不变,但现在依赖于IUser接口:

    public class UserController : Controller
    {
        readonly IUsers _users;
    
        public UserController(IUsers users)
        {
            _users = users;
        }
    
        public ActionResult Index()
        {
            User user = _users.Get(10);
            return View(users);
        }
    }
    

3 个答案:

答案 0 :(得分:3)

存储库是数据库的网关。它们包含尽可能少的代码(没有业务),只需要从数据库中获取数据(或将数据保存到数据库中)。

由于它直接耦合到您的数据库,因此您无法对其进行单元测试。你只能在抽象逻辑时对其进行单元测试,但这正是存储库的用途,因此这是一种无用的抽象。

相反,为它们编写集成测试,设置数据库事务并调用真实存储库并在完成后回滚该事务。

答案 1 :(得分:0)

编写一个返回相应数据的模拟IUserRepository,但老实说,您可以轻松地在EF4中模拟基础数据,这样您就可以直接在控制器中测试您的EF查询。在EF4中,您使用实现IObjectSet的伪ObjectSet替换ObjectSet - 我相当确定使用EF5可以对DbSet执行相同的操作。

答案 2 :(得分:0)

如果我们使用Unity。我们可以在中间层实现Unity容器的扩展,并在Presentation层中注册,如下所示。

          //Data Layer dependency mapping as extension eg : IUnitOfWork
            container.AddNewExtension<DependencyInjectionExtension>();

更多详情请关注文章。

N-tier with DI (Unity)

由于