我已经在一些教程之后实现了UnitOfWork和GenericRepository。
我有IEFDbContext / EFDbContext类来处理数据库,我的IUnitofWork如下...
public interface IUnitOfWork : IDisposable
{
IGenericRepository<TEntity> GetRepository<TEntity>() where TEntity : class;
void Save();
}
和IGenericRepository如下
public interface IGenericRepository<T> where T : class
{
IQueryable<T> Get();
T GetByID(object id);
void Add(T entity);
void Delete(T entity);
void DeleteAll(IEnumerable<T> entity);
void Update(T entity);
bool Any();
}
我的控制器如下......
public class ProjectController : Controller
{
private IGenericRepository<Project> ProjectRepo { get; set; }
private IUnitOfWork _unitOfWork { get; set; }
public ProjectController(IUnitOfWork uow)
{
_unitOfWork = uow;
ProjectRepo = _unitOfWork.GetRepository<Project>();
}
}
我的创建操作如下
[HttpPost]
public ActionResult Create(AddProjectModel model)
{
if (ModelState.IsValid)
{
ProjectRepo.Add(newProject);
_unitOfWork.Save();
}
}
当我运行应用程序时,一切正常,我知道为什么要使用IuitofWork和GenericRepository,这就是为什么我不创建IProjectRepository然后在这里注入...
我的问题是单元测试此操作。
我在我的Test项目中创建了MockGenericRepository和MockUnitofWork,如下所示......
public class MockUnitOfWork<TContext> : IUnitOfWork where TContext : class, new()
{
private TContext _ctx;
private Dictionary<Type, object> _repositories;
public MockUnitOfWork()
{
_ctx = new TContext();
_repositories = new Dictionary<Type, object>();
}
public IGenericRepository<TEntity> GetRepository<TEntity>() where TEntity : class
{
if (_repositories.Keys.Contains(typeof(TEntity)))
{
return _repositories[typeof(TEntity)] as IGenericRepository<TEntity>;
}
var entityName = typeof(TEntity).Name;
var prop = _ctx.GetType().GetProperty(entityName);
MockRepository<TEntity> repository = null;
if (prop != null)
{
var entityValue = prop.GetValue(_ctx, null);
repository = new MockRepository<TEntity>(entityValue as List<TEntity>);
}
else
{
repository = new MockRepository<TEntity>(new List<TEntity>());
}
_repositories.Add(typeof(TEntity), repository);
return repository;
}
public void SetRepositoryData<TEntity>(List<TEntity> data) where TEntity : class
{
IGenericRepository<TEntity> repo = GetRepository<TEntity>();
var mockRepo = repo as MockRepository<TEntity>;
if (mockRepo != null)
{
mockRepo._context = data;
}
}
public void Save()
{
}
public void Dispose()
{
}
}
MockGenericRepository如下
public class MockRepository<T> : IGenericRepository<T> where T : class
{
public List<T> _context;
public MockRepository(List<T> ctx)
{
_context = ctx;
}
public IQueryable<T> Get()
{
return _context.AsQueryable();
}
public T GetByID(object id)
{
// return _context.Find(s => s.Id == id).SingleOrDefault();
throw new NotImplementedException();
}
public virtual void Add(T entity)
{
_context.Add(entity);
}
public virtual void Delete(T entity)
{
_context.Remove(entity);
}
public virtual void DeleteAll(IEnumerable<T> entity)
{
_context.RemoveAll(s => s == entity);
}
public virtual void Update(T entity)
{
var entry = _context.Where(s => s == entity).SingleOrDefault();
entry = entity;
}
public virtual bool Any()
{
return _context.Any();
}
}
我的ProjectControllerTest如下......
public class ProjectControllerTest
{
private readonly List<ALCProject> _projectsList;
private readonly IUnitOfWork _mockU = new MockUnitOfWork<EFDbContext>();
private ProjectController GetControllerObject()
{
foreach (var project in _projectsList)
{
_mockU.GetRepository<Project>().Add(project);
}
var controller = new ProjectController(_mockU);
return controller;
}
[Fact]
public void TestCreateProject()
{
var controller = GetControllerObject();
var result = controller.Create(new AddProjectModel());
Assert.Equal(_mockU.GetRepository<Project>().Get().Count(),4);
}
我遇到的问题是我的测试确实通过但是当我查看_mockU.GetRepository()时.Get()我可以看到添加了一个新项目,但“ID”字段为0,我理解的原因是这是因为我的MockGenericRepsoiotry将上下文定义为public List _context;这就是为什么它只是在列表中添加新项目。
有人可以指导我如何才能生成新ID我觉得我必须伪造EFDbContext但我不知道怎么做???
答案 0 :(得分:1)
项目的Id为0,因为没有任何东西可以将其设置为其他任何内容!实体的Id属性很可能映射到数据库中的标识列(SQL Server作为猜测)。调用DbContext.Save()
时,它在SQL中执行插入操作。 SQL Server正在为该行生成一个新的唯一Id值,并将其返回到Entity Framework。 EF然后将值填充回它持久存在的对象中。
你的模拟工作单元实际上并没有调用DbContext.Save()
,尽管它正在使用EF上下文作为它返回的存储库的数据存储。您可以通过在MockUnitOfWork<T>.Save()
方法中放置代码来为任何存储库中值为零的任何Id属性提供数字来增强它。
或者,正如你所说,这是一个单元测试,所以也许你不应该关心。
我不明白为什么你的工作单元模拟正在查看Entity Framework上下文。为什么不总是根据List<TEntity>
?