我正在使用 Moq
框架进行 Mocking。
我有一个 SocialWorker
派生自 abstract DataWorker
类。
SocialWorker
引用了几个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>()
总的来说,我对最小起订量和单元测试还很陌生。
下面是相关代码供大家引用:
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()
{
. . .
}
}
数据存储库
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)
{
. . .
}
}
社工
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 的用途。您的设计有 SocialWorker
,其属性提供 PlaceRepository
,那么 PlaceManager
的用途是什么,为什么要将它传递给 SocialWorker
? SocialWorker
不管理自己的 PlaceRepository
吗?
为什么不调用 _socialWorker.PlaceRepository.Add(place)
,或者更简洁地调用 _socialWorker.Add(place)
?
我只是猜测 PlaceManger
访问了 SocialWorker.PlaceRepository
,但我不明白为什么 SocialWorker.PlaceRepository
是一个公共(public)属性(property),没有什么可以阻止任何人直接使用并忽略 PlaceManager
。如果 PlaceManager
也是 Place
的某种Repository
。
此外,您的 IRepository
代码将 Add()
作为空值,但 PlaceManager
返回一个 对象
.为什么这不是 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());
这就是实际调用的内容,因为这是存储库中方法的签名。只能检查接口(interface)方法是否被调用。
关于c# - Moq、抽象类和虚拟属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10050168/