今天我想开始对一个小的asp.net MVC 3 Web(测试)应用程序进行单元测试,以学习一些新东西。
但事情变得比我预期的要糟糕......
我现在已经阅读了一些关于与Entity框架相关的单元测试的线程,现在我首先要为我的实体框架相关类实现接口,这样我就可以在内存“数据库”中实现我的单元测试。
我的代码库来自ASP.NET MVC tutorial。我读过MSDN但在我的案例中对我没有帮助。
我想告诉你我的代码。我正在使用带有存储库的工作模式单元:
工作单位:
public class SqlUnitOfWork : IUnitOfWork, IDisposable
{
private SqlContext context = new SqlContext();
private IGenericRepository<Message> messageRepository;
private IGenericRepository<Receipt> receiptRepository;
private IGenericRepository<Useraccount> useraccountRepository;
private bool disposed = false;
public IGenericRepository<Message> MessageRepository
{
get
{
if (this.messageRepository == null)
{
this.messageRepository = new SqlGenericRepository<Message>(context);
}
return messageRepository;
}
}
public IGenericRepository<Receipt> ReceiptRepository
{
get
{
if (this.receiptRepository == null)
{
this.receiptRepository = new SqlGenericRepository<Receipt>(context);
}
return receiptRepository;
}
}
public IGenericRepository<Useraccount> UseraccountRepository
{
get
{
if (this.useraccountRepository == null)
{
this.useraccountRepository = new SqlGenericRepository<Useraccount>(context);
}
return useraccountRepository;
}
}
public SqlUnitOfWork()
{
}
~SqlUnitOfWork()
{
}
public virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Save()
{
context.SaveChanges();
}
}
这个实现了我创建的接口。
我的sql通用存储库:
public class SqlGenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
internal SqlContext context;
internal DbSet<TEntity> dbSet;
public SqlGenericRepository(SqlContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
~SqlGenericRepository()
{
}
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
public virtual TEntity GetByID(object id)
{
return dbSet.Find(id);
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Delete(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
}
它实现了我编程的接口:
public interface IGenericRepository<TEntity> where TEntity : class
{
IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "");
TEntity GetByID(object id);
void Insert(TEntity entity);
void Delete(object id);
void Delete(TEntity entityToDelete);
void Update(TEntity entityToUpdate);
}
我现在想为单元测试实现一个“InMemoryGenericRepository”,然后是“InMemoryUnitOfWork”。 那些“InMemoryGenericRepository”看起来怎么样?
我想我会在这个存储库中使用通用List来存储所有数据:
IEnumerable<TEntity> List { get; set; }
但我怎样才能适应这种方法:
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
所以它正在使用我的
IEnumerable<TEntity> List { get; set; }
我希望你能在我的问题结束前完成。
答案 0 :(得分:1)
如果您的课程是POCO,那么他们看起来像这样:
namespace Project.Model // auto-generated Foo.cs
{
public partial class Foo // notice partiality
{
}
}
然后你写下这个:
namespace Project.Model // custom Foo.cs in another folder
{
public partial class Foo : IEntity // notice interface
{
}
}
答案 1 :(得分:0)
你也可以用:
重写你的懒惰属性private IGenericRepository<Message> messageRepository;
public IGenericRepository<Message> MessageRepository
{
get
{
return messageRepository ?? (messageRepository = new IGenericRepository<Message>());
}
}
或
private Lazy<IGenericRepository<Message>> messageRepository = new Lazy<IGenericRepository<Message>>(new IGenericRepository<Message>()));
public IGenericRepository<Message> MessageRepository
{
get
{
return messageRepository.Value;
}
}
答案 2 :(得分:0)
通用存储库模式不是一个好模式。它会给你带来很大的痛苦,以换取存储独立性(你可能不需要它。你喜欢拥有它,但你真的不需要它)。您将真的很难编写可查询的内存存储库,原因如下:
此外,通过抽象出您的ORM,您可以使用其功能的 none 。您只能使用最通用和一般的功能。
几年前我完成了这件事,痛苦并没有结束。我发现使用真正的SQL数据库进行测试是一个很好的模式。这样你就不需要任何存储库,可以测试真实的东西。这有它的问题,但它是可行的。这个问题的解决方案是放弃通用存储库模式。