私はフレームワークを使ってモッキングしています。Moq、抽象クラスと仮想プロパティ
abstract DataWorker
クラスに由来するSocialWorker
があります。
SocialWorker
は、私は次のテストを実行しようとしていますvirtual property
としてRepositories
のカップルへの参照を持っています
private Place _place;
private Mock<IRepository<Resources.Data.Place>> _placeRepositoryMock;
private Mock<SocialWorker> _socialWorkerMock;
[SetUp]
public void SetUp()
{
_place = new Place {Name = "A"};
_socialWorkerMock = new Mock<SocialWorker> {DefaultValue = DefaultValue.Mock};
IRepository<Resources.Data.Place> placeRepository = _socialWorkerMock.Object.PlaceRepository;
_placeRepositoryMock = Mock.Get(placeRepository);
_placeRepositoryMock.Setup(
repository =>
repository.Find(It.IsAny<Expression<Func<Resources.Data.Place, bool>>>(), null, null))
.Returns(new[] {new Resources.Data.Place()});
}
[Test]
public void AddShouldAddANewPlace()
{
var placeManager = new PlaceManager(_socialWorkerMock.Object);
object placeEntity = placeManager.Add(_place);
placeEntity.GetType().Should().Equal(typeof (Resources.Data.Place));
_socialWorkerMock.Verify(
socialWorker => socialWorker.PlaceRepository.Add(It.IsAny<Resources.Data.Place>()), Times.Once());
_placeRepositoryMock.Verify(
placeRepository =>
placeRepository.Find(p => p.Name.Equals(_place.Name), null, null).First(),
Times.Once());
}
このテストの最後の検証は、このエラーで失敗します。
System.NotSupportedException : Invalid verify on a non-virtual (overridable in VB) member: placeRepository => placeRepository.Find(p => p.Name.Equals(._place.Name), null, null).First<Place>()
私は一般的にMoqと単体テストにはかなり新しいです。
IUnitOfWork
public interface IUnitOfWork : IDisposable
{
void CommitChanges();
}
IRepository
public interface IRepository<T>
{
void Add(T entity);
void Delete(T entity);
IEnumerable<T> Find(Expression<Func<T, bool>> filter = null,
Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
IList<string> includedProperties = null);
T FindById(object id);
void Update(T entity);
}
DataWorker
public abstract class DataWorker : IUnitOfWork
{
protected ObjectContext ObjectContext;
private bool _disposed;
protected DataWorker()
{
ObjectContext = new ObjectContext(ConfigurationManager.ConnectionStrings["DataEntities"].ConnectionString);
}
~DataWorker()
{
. . .
}
protected virtual void Dispose(bool disposing)
{
. . .
}
public virtual void CommitChanges()
{
ObjectContext.SaveChanges();
}
public void Dispose()
{
. . .
}
}
:ここ
はあなたの参照のために関連するコードです
DataRepository
public class DataRepository<T> : IRepository<T> where T : EntityObject
{
private readonly ObjectSet<T> _objectSet;
public DataRepository(ObjectContext objectContext)
{
_objectSet = objectContext.CreateObjectSet<T>();
}
public void Add(T entity)
{
. . .
}
public void Delete(T entity)
{
. . .
}
public virtual IEnumerable<T> Find(Expression<Func<T, bool>> filter = null,
Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
IList<string> includedProperties = null)
{
. . .
}
public T FindById(object id)
{
. . .
}
public void Update(T entity)
{
. . .
}
}
SocialWorker
public class SocialWorker : DataWorker
{
private IRepository<ContactRequest> _contactRequestRepository;
private IRepository<Place> _placeRepository;
private IRepository<User> _userRepository;
public virtual IRepository<ContactRequest> ContactRequestRepository
{
get
{
return _contactRequestRepository ??
(_contactRequestRepository = new DataRepository<ContactRequest>(ObjectContext));
}
}
public virtual IRepository<Place> PlaceRepository
{
get { return _placeRepository ?? (_placeRepository = new DataRepository<Place>(ObjectContext)); }
}
public virtual IRepository<User> UserRepository
{
get { return _userRepository ?? (_userRepository = new DataRepository<User>(ObjectContext)); }
}
}
これはMVCアプリケーションです。私は自分のコントローラから直接_socialWorker.PlaceRepository.Add(場所)を呼び出すことができました。しかし、コントローラをできるだけ薄く保つことを好みます。さらに、 'PlaceManager'は通常の' CRUD'以上のことをします。たとえば、Yahoo!のPlaceFinderサービスから関連する場所を探すなどです。さらに 'PlaceManager'が存在するので、将来、Services/APIモジュールは' UnitWorker'や 'Repository'に対してコードを直接記述することなく、同じビットのコードにアクセスすることができます。 – Moon
'PlaceManager'と' PlaceRepository'の違いはまだわかりません。いつPlaceManagerに直接アクセスするのか、PlaceManagerを介してアクセスするのでしょうか?(結局のところ、 'PlaceManager'を無視する人はいません)。 'PlaceManager'が' PlaceRepository'を担当しないのはなぜですか?それは本当に私の匂いのように思えます、それはSRPに従っていないようです(ソーシャルワークはあまりにも多くのことをしており、 'Place'sは分割されています)。 'Place'は少なくとも2か所で追加できますが、私は全体的なデザインコンセプトを理解していないので、私にとって混乱しているようです。 – nicodemus13
私のコントローラは、ワーカーまたはリポジトリが存在することさえ知りません。彼らがアクセスできるのはマネージャーだけです。 – Moon