随着我深入研究DbContext,DbSet和相关接口,我想知道为什么你需要围绕这些实现实现一个单独的"通用"存储库?
它看起来像DbContext和IDbSet做你需要的一切,并在DbContext中包含"工作单元".
我在这里遗漏了什么,或者似乎人们喜欢无缘无故地添加另一层依赖.
如果您要激发为什么要将ORM用于管理/客户的"优点",原因是什么?
尝试并保持每个答案的一个原因,以便我们可以看到被投票的最佳理由
我正在使用本教程伪造我的DbContext并测试:http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic -repository /
但我必须更改FakeMainModuleContext实现以在我的控制器中使用:
public class FakeQuestiona2011Context : IQuestiona2011Context
{
private IDbSet<Credencial> _credencial;
private IDbSet<Perfil> _perfil;
private IDbSet<Apurador> _apurador;
private IDbSet<Entrevistado> _entrevistado;
private IDbSet<Setor> _setor;
private IDbSet<Secretaria> _secretaria;
private IDbSet<Pesquisa> _pesquisa;
private IDbSet<Pergunta> _pergunta;
private IDbSet<Resposta> _resposta;
public IDbSet<Credencial> Credencial { get { return _credencial ?? (_credencial = new FakeDbSet<Credencial>()); } set { } }
public IDbSet<Perfil> Perfil { get { return _perfil ?? (_perfil = new FakeDbSet<Perfil>()); } set { } }
public IDbSet<Apurador> Apurador { get …Run Code Online (Sandbox Code Playgroud) 我是针对ADO .NET实体框架编写的单元测试代码.我想用行填充内存数据库,并确保我的代码正确检索它们.
我可以使用Rhino Mocks来模拟实体框架,但这还不够.我会告诉查询返回给我的实体.这既不会测试where子句,也不会测试.Include()语句.我想确保我的where子句只匹配我想要的行,而不是其他行.我想确定我已经要求我需要的实体,而不是我没有.
例如:
class CustomerService
{
ObjectQuery<Customer> _customerSource;
public CustomerService(ObjectQuery<Customer> customerSource)
{
_customerSource = customerSource;
}
public Customer GetCustomerById(int customerId)
{
var customers = from c in _customerSource.Include("Order")
where c.CustomerID == customerId
select c;
return customers.FirstOrDefault();
}
}
Run Code Online (Sandbox Code Playgroud)
如果我模拟ObjectQuery以返回一个填充了订单的已知客户,我怎么知道CustomerService有正确的where子句和Include?我宁愿插入一些客户行和一些订单行,然后断言选择了正确的客户并填充了订单.
我目前正在为MVC4应用程序中的存储库实现编写单元测试.为了模拟数据上下文,我开始采用这篇文章中的一些想法,但我现在发现了一些限制,让我怀疑是否有可能正确模拟IQueryable.
特别是,我已经看到了一些测试通过但代码在生产中失败的情况,并且我无法找到任何方法来模拟导致此失败的行为.
例如,以下代码段用于选择Post属于预定义类别列表的实体:
var posts = repository.GetEntities<Post>(); // Returns IQueryable<Post>
var categories = GetCategoriesInGroup("Post"); // Returns a fixed list of type Category
var filtered = posts.Where(p => categories.Any(c => c.Name == p.Category)).ToList();
Run Code Online (Sandbox Code Playgroud)
在我的测试环境中,我试图嘲弄posts使用假DbSet上面提到的实施,同时也通过创建List的Post实例并将其转换为IQueryable使用AsQueryable()扩展方法.这两种方法都在测试条件下工作,但代码实际上在生产中失败,但有以下例外:
System.NotSupportedException : Unable to create a constant value of type 'Category'. Only primitive types or enumeration types are supported in this context.
虽然像这样的LINQ问题很容易解决,但真正的挑战是找到它们,因为它们不会在测试环境中显示出来.
我期望我可以嘲笑实体框架的实施行为,这是不现实的IQueryable吗?
谢谢你的想法,
蒂姆.
想知道我是否需要使用Genericrepository模式和UnitOfWork来模拟存储库.我正在使用MOQ.Is它现在是多余的,因为我注意到EF 4.1有IDBSet.
我还没弄明白如何编写一些通用的IDBSet.如果你有一个实例IDBSet的例子,你能告诉我吗?
有什么建议?
unit-testing mocking unit-of-work repository-pattern entity-framework-4.1
好吧,不确定这是否是正确的标题,但基本上我在使用MVC应用程序中的存储库时遇到了很多问题,您可以用另一组存储库替换一组存储库,实现不同的数据存储技术.
例如,假设我想为我的应用程序使用Entity Framework.但是,我还希望在硬编码列表中实现一组测试数据.我想有一组接口(IUserRepository,IProductRepository等 - 我们暂不讨论现在更通用的IRepository <T>)这两种方法都可以实例化.然后,使用(比方说)Ninject或Castle Windsor等依赖注入工具,我可以在实体框架提供程序(访问实际数据库)和测试提供程序(访问列表)之间来回切换.
简而言之,问题在于:
- 如果要使用Entity Framework,则希望您的存储库返回IQueryable <SomeType>.
- 如果你打算使用硬编码列表,你不希望你的存储库返回IQueryable,因为它大大增加了开销,而且,Linq to Entities与Linq到Objects有很大的不同,导致代码中的许多麻烦这两个提供商都很常见.
换句话说,我发现最好的方法是隔离存储库中所有依赖于EF的代码,以便存储库本身返回IEnumerable或IList或其他类似的东西 - 然后EF和其他一些技术都可以使用相同的存储库.因此,所有IQueryable都将包含在EF存储库中.这样,您可以将Linq实体与EF存储库一起使用,将Linq添加到具有测试存储库的对象.
然而,这种方法将大量的业务逻辑放入存储库中,并导致许多重复的代码 - 即使实现有些不同,逻辑也必须在每个存储库中重复.
存储库作为这个非常薄的层并且只是连接到数据库的整个想法随后丢失 - 存储库是业务逻辑的"存储库"以及数据存储连接.你不能只有查找,保存,更新等.
我无法解决需要隔离提供程序相关代码和在集中位置拥有业务逻辑之间的这种差异.
有任何想法吗?如果有人能够指出一个解决这个问题的实现的例子,我将非常感激.(我已经阅读了很多内容,但找不到任何专门讨论这些问题的内容.)
更新:
我想我开始觉得可能不可能为不同的提供者换出存储库 - 例如,如果你要使用Entity Framework,你只需将整个应用程序用于实体框架.单元测试?我正在努力解决这个问题.到目前为止,我的做法是使用硬编码数据建立一个单独的存储库,并将其用于单元测试,以及在设置数据库之前测试应用程序本身.我想我将不得不寻找一个不同的解决方案,也许是一些嘲弄工具.
但后来提出了为什么使用存储库的问题,特别是为什么使用存储库接口.我正在研究这个问题.我认为确定最佳实践是需要进行一些研究.
asp.net-mvc design-patterns entity-framework repository-pattern
假设我们已经创建了实体模型,使用它的首选方法是什么?我个人无法下定决心..
使用ModelAdapter:
public stati? Product[] GetProducts()
{
using(Entities ctx = new Entities())
{
return ctx.Product.ToArray();
}
}
Product[] ps = ModelAdapter.GetProducts();
// ...
ModelAdapter.UpdateProduct(p);
Run Code Online (Sandbox Code Playgroud)
使用上下文:
using(Entities ctx = new Entities())
{
Product[] ps = ctx.Product.ToArray();
// ...
ctx.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
混合模式,折衷?
扩展方法:
using(Entities ctx = new Entities())
{
Product[] ps = ctx.GetProducts();
// ...
ctx.UpdateProduct(p);
}
Run Code Online (Sandbox Code Playgroud)实际上现在,我正在尝试方法#4,实现实用程序方法作为上下文的扩展.所以我可以使用一个上下文,并对这个上下文进行多次调用.
我对单元测试有疑问.
假设我有一个带有一个create方法的控制器,它将新客户放入数据库中:
//code a bit shortened
public actionresult Create(Formcollection formcollection){
client c = nwe client();
c.Name = formcollection["name"];
ClientService.Save(c);
{
Run Code Online (Sandbox Code Playgroud)
Clientservice将调用datalayer对象并将其保存在数据库中.
我现在所做的是创建一个数据库测试脚本,并在测试之前将我的数据库设置为已知状态.所以当我在单元测试中测试这个方法时,我知道数据库中必须有一个客户端,它的名字是什么.简而言之:
ClientController cc = new ClientController();
cc.Create(new FormCollection (){name="John"});
//i know i had 10 clients before
assert.areEqual(11, ClientService.GetNumberOfClients());
//the last inserted one is John
assert.areEqual("John", ClientService.GetAllClients()[10].Name);
Run Code Online (Sandbox Code Playgroud)
所以我读过单元测试不应该打到数据库,我已经为数据库类设置了一个IOC,但那又是什么?我可以创建一个假的数据库类,并使它什么都不做.
但是当然我的断言不起作用,因为如果我说它GetNumberOfClients()总是返回X,因为它与Create Method中使用的假数据库类没有交互.
我还可以在假数据库类中创建一个客户端列表,但由于将创建两个不同的实例(一个在控制器操作中,一个在单元测试中),它们将没有交互.
如果没有数据库,这个单元测试工作的方法是什么?
编辑:客户端服务不直接连接到数据库.它调用ClientDataClass,它将连接到数据库.因此ClientDatabaseClass将被替换为假的
Dunno如何恰当地命名.我在m:n关系中有两个实体:成员和角色.
public class Role
{
public int Id { get; set; }
public string Title { get; set; }
public ICollection<Member> MembersInRole { get; set; }
}
public class Member
{
public int Id { get; set; }
public string Name { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public ICollection<Role> Roles { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我已经制作了一些种子数据:http :
//i56.tinypic.com/2vjvj1w.png
并写了测试:http :
//i54.tinypic.com/112916b.png
问题是,我的会员实体没有分配角色,即使我在上下文中创建它们(如图所示).我不知道出了什么问题.数据库中的表似乎没问题.我不确定上下文实例是否有问题.但它应该没问题,因为我一直在处理种子数据.
entity-relationship many-to-many entity-framework ef-code-first entity-framework-4.1
asp.net-mvc ×3
unit-testing ×3
.net ×2
database ×2
mocking ×2
unit-of-work ×2
c# ×1
coding-style ×1
iqueryable ×1
many-to-many ×1
orm ×1
rhino-mocks ×1
tdd ×1
testing ×1