32

因爲我想單元測試我的代碼,所以我在我的MVC4應用程序中實現了存儲庫模式。我設法創建了一個Context Interface,一個假的Context,並通過遵循this的代碼使用僞造的System.Data.Entity.DbSet實現。如何使用存儲庫模式在實體框架中僞造DbContext.Entry方法

不幸的是,就像我之前的兩張海報(herehere),我無法嘲笑DbContext.Entry method。我用這個方法對我的代碼更新數據庫條目如下:

DbContext.Entry(order).State = EntityState.Modified; 

我還沒有找到一個解決這個問題,只有誰說這樣的話的人:

「,什麼是點單元測試這段代碼?你假冒了Find 的方法,那麼你假冒DbEntityEntry並且將不會有真正的邏輯來 測試。「

閱讀this和所有鏈接的問題,然後再繼續。 (...)如果要測試存儲庫,請創建與真實數據庫交談的集成測試。

這一切都很好,但仍然沒有回答這個問題。我讀了評論,並且仍然希望使用這種Entry方法,這樣我就可以使用僞造的上下文,並在我的單元測試中使用模擬對象。當然,我也會使用集成測試,但它們不如一些快速單元測試那麼快。

我收到的時候我嘗試一些實現的錯誤是,Error 2 'Project.Models.Order' does not contain a definition for 'State' and no extension method 'State' accepting a first argument of type '[whatever return type I use]' could be found (are you missing a using directive or an assembly reference?)

我希望有人能幫助我做一個假DbContext.Entry方法。

+0

使用存儲庫模式,其中庫實現再加上工作模式的單元的通用接口。這樣,你只需要嘲笑或僞造工作單元。 – Maess

+0

我看了你鏈接到的兩個SO帖子中的第一個,並且有一個被忽略的答案。但它可能與你的問題完全不相關。請發佈*您的*代碼,以便我可以提供一個很好的答案。 –

+0

@KeithPayne有答案嗎? –

回答

30

通過「添加間接的附加級別」找到了答案here我們得到:

public void SetModified(object entity) 
{ 
    Entry(entity).State = EntityState.Modified; 
} 

,並在我們的控制器使用DbContext.SetModified(entity)

2

如何實現基於接口的存儲庫和工作單位得到你所追求的一個例子:

public interface IRepository<T> 
    { 
     T FindSingle(Expression<Func<T, Boolean>> predicate, params Expression<Func<T, object>>[] includeExpressions); 
     void ProxyGenerationOn(); 
     void ProxyGenerationOff(); 
     void Detach(T entity); 
     void Add(T newEntity); 
     void Modify(T entity); 
     void Attach(T entity); 
     void Remove(T entity); 
     void SetCurrentValues(T modifiedEntity, T origEntity); 
     T GetById(int id); 
     T GetById(int id, bool sealOverride); 
     IQueryable<T> GetAll(); 
     IQueryable<T> GetAll(bool sealOverride); 
     IQueryable<T> GetAll(string[] EagerLoadPaths); 
     IQueryable<T> Find(Expression<Func<T, Boolean>> predicate); 
    } 



public interface IUnitOfWork : IDisposable 
    { 
     //repository implementations go here 
     bool SaveChanges() 
    } 

注意如何上下文完全抽象化了。你只需要在具體實現中擔心它。

+3

詳細說明:OP應該在他的Modify()實現中調用DbContext.Entry(entity).State = EntityState.Modified;'。然後,在使用存儲庫測試代碼時,您只需嘲笑存儲庫並驗證'repository.Modify()'被調用_。 – CodeCaster

+0

@CodeCaster這是一個很好的解釋。 –

+0

@Maess我對此很陌生,作品的單位只是抽象出來的方法調用?例如,我不直接使用'DbContext.SaveChanges',而是'repository.SaveChanges',上下文位於我實例化的倉庫中? –

3

爲了解決這個我添加了一個方法重載,並增加了一個過時的屬性一看,原來方法被調用的位置。

public virtual void Entry<TEntity>(TEntity entity, Action<DbEntityEntry<TEntity>> action) where TEntity : class 
    { 
     action(base.Entry(entity)); 
    } 

    [Obsolete("Use overload for unit tests.")] 
    public new DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class 
    { 
     return base.Entry(entity); 

     /** or **/ 

     throw new ApplicationException("Use overload for unit tests."); 
    } 

那麼你可以DbContext.Entry(order, ent => ent.State = EntityState.Modified;

相關問題