最小起订量、抽象类和虚拟属性

本文关键字:抽象类 虚拟 属性 | 更新日期: 2023-09-27 18:30:23

我正在使用Moq框架进行模拟。

我有一个SocialWorker,它来自一个abstract DataWorker类。

SocialWorker将几个Repositories作为virtual property

我正在尝试运行以下测试:

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>()

我对最小起订量和单元测试相当陌生。

以下是相关代码供您参考:

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)); }
    }
}

最小起订量、抽象类和虚拟属性

我对你的代码试图做什么感到困惑,设计似乎有点奇怪。

首先,您遇到的测试是引用类PlaceManager,您尚未指定,并且由于这是测试的一部分,因此很难看出它出了什么问题。

此外,我不确定PlaceManager的用途。 您的设计与提供PlaceRepository的属性SocialWorker,那么PlaceManager是干什么的,为什么要通过SocialWorkerSocialWorker不管理自己的PlaceRepository吗?

你为什么不叫_socialWorker.PlaceRepository.Add(place),或者更整齐地_socialWorker.Add(place)

我只是猜测PlaceManger访问SocialWorker.PlaceRepository,但我不明白为什么由于SocialWorker.PlaceRepository是公共财产,没有什么可以阻止任何人直接使用并忽略PlaceManager。 也就是说,如果PlaceManager也是某种Place Repository.

此外,您的IRepository代码已Add()为空,但PlaceManager返回object。 为什么这不强类型Place? 看来这就是你所期待的... 并且您的PlaceManager.Add()方法返回一个Place,尽管Repository Add()方法是void。(在它被持久化到上下文之后,它是同一个地方吗? 您的PlaceManager是否在对Place做其他事情?

也许我有错误的棍子末端? 您能否进一步澄清代码的意图是什么,而不是它的作用? 很抱歉有这么多问题,但我想知道你的设计应该做什么,然后再弄清楚你为什么要针对非虚拟的......

我认为特定问题的原因是,在您的验证中,您期望对Find进行验证,但是,这包括对First()的调用,这需要被嘲笑,不能,因为它是一种静态扩展方法,不是虚拟的或抽象的。

无论如何,我不知道你为什么要反对First()。 您要验证的方法只是:

_placeRepositoryMock.Verify(placeRepository =>
   placeRepository.Find(p => p.Name.Equals(_place.Name), null, null),
   Times.Once());

这就是实际调用的内容,因为这是存储库中方法的签名。 您只能检查是否调用了接口方法。