2014-12-01 96 views
0

我已经用C#,MVC,实体框架,LINQ等编写了一个Web应用程序......现在我想追溯地为整个项目创建单元测试。为单元测试创​​建存储库

据我所知,为了编写有效的单元测试,我需要为模型创建存储库,以便它们可以被模拟,因此实体框架将对数据库执行任何命中。

我有3个主要模型;类别,密码,用户密码。

类别包含类别和密码。密码包含UserPasswords(链接到用户帐户)。所以我创建了3个存储库,其基本方法如:创建,删除,更新等..

然而,看着这个LINQ查询:

var selectedCategoryItem = DatabaseContext.Categories 
       .Where(c => c.CategoryId == ParentCategoryId) 
       .Include(c => c.SubCategories) 
       .Include(c => c.Passwords) 
       .Include(c => c.Passwords.Select(p => p.Creator)) 
       .ToList() 
       .Select(c => new Category() 
       { 

       SubCategories = c.SubCategories 
          .Where(sub => !sub.Deleted) 
          .OrderBy(sub => sub.CategoryOrder) 
          .ToList(),       //make sure only undeleted subcategories are returned 

       Passwords = c.Passwords 
          .Where(pass => !pass.Deleted 
          && (
          (UserPasswordList.Any(up => up.PasswordId == pass.PasswordId && up.Id == UserId)) 
          || (userIsAdmin && ApplicationSettings.Default.AdminsHaveAccessToAllPasswords) 
          || pass.Creator_Id == UserId 
          ) 
          ) //make sure only undeleted passwords - that the current user has acccess to - are returned 
          .OrderBy(pass => pass.PasswordOrder) 
          .ToList(), 

       CategoryId = c.CategoryId, 
       CategoryName = c.CategoryName, 
       Category_ParentID = c.Category_ParentID, 
       CategoryOrder = c.CategoryOrder, 
       Parent_Category = c.Parent_Category, 
       Deleted = c.Deleted 
       }) 
       .SingleOrDefault(); 

如果仓库只是像保存,更新,删除,插入,FindById等基本方法....我应该如何将查询分解成存储库?这里还有很多商业逻辑,例如过滤用户可以访问的密码,应该在哪里?

我读了一些关于返回IQueryable对象的信息,以便可以在服务层中更改LINQ查询......看起来如何?

+1

你看着努力呢? HTTPS://effort.codeplex。com/ – Bringer128 2014-12-02 01:19:16

回答

2

如果你想要编写单元测试,所有的LINQ到实体的,应该是一个接口之后,

例如

public interface ICategoryRepository { 
    List<Category> GetCategoriesForParentId(int id); 
} 

然后是一个实现该方法并包含LINQ和过滤逻辑的类。

现在在需要访问它的客户端类中,通过构造函数传入ICategoryRepository(推荐)。对于单元测试,将一个模拟库传入构造函数,该构造函数返回一个预定义的结果集。

为了测试实际的存储库过滤/转换逻辑,我发现最好的方法是使用SQLite或SQL CE,并进行集成测试,该测试加载预定义的数据库,该数据库处于已知状态从保存的副本,或重新创建它每次测试),并有一个集成测试,在SQLite的或SQL CE数据库指向存储库类,而不是你真正的使之始终处于已知状态,运行查询,检查结果集。

编辑:

无论是通过由库需要进入方法的细节,如:

List<Category> GetCategoriesForParentIdAnduser(int id, int passwordId, int userId); 

或者,如用户可能是整个网站,你可以通过一个

public interface IUserConfig { 
    int PasswordId{ get; set; } 
    int UserId { get; set;} 
} 


// Constructor for CategoryRepository : ICategoryRepository 
public CategoryRepository(DbContext context, IUserConfig) 
{ 
    .... 
} 

然后

public List<Category> GetCategoriesForParentId(int id){ 
    return _context.Categories 
       ..... 
       Passwords = c.Passwords.Where(
          ..... 
          (UserPasswordList.Any(up => up.PasswordId == _userConfig.PasswordId 
                && up.Id == _userConfig.UserId))        
       ..... 
} 

编辑2:刚注意到.SingleOrDefault(),而不是返回List<Category>你会返回Category

+0

我不能理解的是,让我们拿列表 GetCategoriesForParentId - 这将返回一个类别列表,但我需要返回一个类别和密码列表...所以这将如何使用存储库模式实现? – binks 2014-12-01 23:41:26

+0

2个仓库,2个电话 – 2014-12-01 23:42:52

+0

因此,类似于: var root = new Category(){subcategories = GetCategoriesForParentId(1),password = GetPasswordsForParentId(1)}; – binks 2014-12-01 23:43:58