コードを単体テストするため、MVC4アプリケーションにリポジトリパターンを実装しました。コンテキストインターフェイス、偽のコンテキストを作成し、 _System.Data.Entity.DbSet
_ の偽の実装を使用して、 this のコードを実行しました。
残念ながら、私の前の2つのポスター( here と here )のように、 _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メソッドを作成するのを手伝ってくれることを願っています。
「間接レベルを追加する」ことで答えが見つかりました here
_public void SetModified(object entity)
{
Entry(entity).State = EntityState.Modified;
}
_
コントローラーでDbContext.SetModified(entity)
を使用します。
これを回避するために、メソッドオーバーロードを追加し、廃止された属性を追加して、元のメソッドが呼び出されている場所を確認しました。
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;
インターフェイスベースのリポジトリと作業単位を実装して、目的を達成する方法の例:
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()
}
コンテキストが完全に抽象化されていることに注目してください。具体的な実装でのみ心配する必要があります。