具象クラスのメンバー(プロパティ、メソッド)を としてマークするとvirtual
、それらのメソッド/プロパティを個別にモックできると思います。(仮想に相当する VB はオーバーライド可能だと思います..?)
Moq は、テストの実行時に実行時に何かの新しい具体的な実装を作成することによって機能します。これが、インターフェイスと抽象クラスでうまく機能する理由です。ただし、インターフェイスまたは抽象クラスがない場合は、メソッドまたはプロパティをオーバーライドする必要があります。
質問の著者の回答への返信:
あなたは自称 TDD 初心者なので、クラスをテスト可能にするためだけにパラメーターなしのコンストラクターをクラスに追加することは、受け入れられる解決策ではないことを指摘したかっただけです。
GenericRepository クラスに Entity Framework の DbSet / IDbSet への強い依存関係を与えることで、リポジトリの実装と EF の間に緊密な結合が作成されます...using System.Data.Entity
そのファイルの上部にある行に注意してください。
コンストラクターの依存関係を追加する場合はいつでも、それをインターフェイスまたは抽象クラスとして追加することを真剣に検討する必要があります。制御していないライブラリのメンバー (EF の DbContext など) にアクセスする必要がある場合は、Morten の回答に従って、独自のカスタム インターフェイスで機能をラップします。
DbContext の場合、このクラスは UnitOfWork 実装を提供するだけではありません。また、データをクエリして、リポジトリ内のアイテムを追加/置換/削除する方法も提供します。
public interface IUnitOfWork
{
int SaveChanges();
}
public interface IQuery
{
IQueryable<TEntity> GetQueryable<TEntity>() where TEntity : class;
}
public interface ICommand : IQuery
{
void Add(object entity);
void Replace(object entity);
void Remove(object entity);
}
次のように、これら 3 つのインターフェイスで DbContext を簡単にラップできます。
public class MyCustomDbContext : DbContext, IUnitOfWork, ICommand
{
// DbContext already implements int SaveChanges()
public IQueryable<TEntity> GetQueryable<TEntity>() where TEntity : class
{
return this.Set<TEntity>();
}
public void Add(object entity)
{
this.Entry(entity).State = EntityState.Added;
}
public void Replace(object entity)
{
this.Entry(entity).State = EntityState.Modified;
}
public void Remove(object entity)
{
this.Entry(entity).State = EntityState.Deleted;
}
}
インターフェイスが に依存しないことに注意してくださいSystem.Data.Entity
。これらは、プリミティブと、 、 、 などの標準の .NET 型を使用object
しIQueryable<T>
ますint
。このようにして、汎用リポジトリの依存関係をインターフェイスに与えると、System.Data.Entity への依存関係を削除できます。
// using System.Data.Entity; // no need for this dependency any more
public class GenericRepository
{
private readonly ICommand _entities;
private readonly IQueryable<TEntity> _queryable;
public GenericRepository(ICommand entities)
{
this._entities = entities;
this._queryable = entities.GetQueryable<TEntity>();
}
//public GenericRepository()
//{
// no need for a parameterless constructor!
//}
}
...そして、GenericRepository は完全に単体テスト可能になりました。これは、これらのインターフェイス メソッドを簡単にモックできるためです。
最終的な注意:
また、あなた自身の質問に対する回答を見た後、あなたの UnitOfWork クラスのプロパティとして CompanyRepository があるようです。次に、UnitOfWork を依存関係として CompanyInformationController に注入します。これは逆です。代わりに、CompanyRepository (またはそのインターフェイス) をコントローラーのコンストラクターに挿入する必要があります。UnitOfWork パターンは、既知のリポジトリの参照を維持することとは関係ありません。関連するアイテムに加えられた複数の変更を追跡して、それらをすべて 1 つのトランザクションとして一度にプッシュできるようにすることです。EF はこれを自動的に行うため、アプリが IQuery、ICommand、または IUnitOfWork の実装を要求するかどうかに関係なく、AutoFac が同じ DbContext インスタンスを提供している限り、UnitOfWork が関係する唯一のメソッドは SaveChanges() です。