我是测试驱动开发的新手,并尝试对mvc应用程序进行单元测试。我正在使用Moq和Ninject,并尝试遵循工作单元存储库模式。我收到所有测试的System.ArgumentException错误。这是错误消息和错误堆栈跟踪:
Test method LOMSv4.Tests.Controllers.AutobytelControllerTest.Index_Contains_All_Requests threw exception:
System.ArgumentException: Can not instantiate proxy of class: LOMSv4_DAL.Autobytel.Concrete.RequestRepository.
Could not find a parameterless constructor.
参数名称:constructorArguments
Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance(Type proxyType, List`1 proxyArguments, Type classToProxy, Object[] constructorArguments)
Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors)
Moq.Proxy.CastleProxyFactory.CreateProxy[T](ICallInterceptor interceptor, Type[] interfaces, Object[] arguments)
Moq.Mock`1.<InitializeInstance>b__0()
Moq.PexProtector.Invoke(Action action)
Moq.Mock`1.InitializeInstance()
Moq.Mock`1.OnGetObject()
Moq.Mock.GetObject()
Moq.Mock.get_Object()
Moq.MockDefaultValueProvider.ProvideDefault(MethodInfo member)
Moq.QueryableMockExtensions.FluentMock[T,TResult](Mock`1 mock, Expression`1 setup)
lambda_method(Closure )
Moq.Mock.GetInterceptor(Expression fluentExpression, Mock mock)
Moq.Mock.<>c__DisplayClass1c`2.<Setup>b__1b()
Moq.PexProtector.Invoke[T](Func`1 function)
Moq.Mock.Setup[T,TResult](Mock mock, Expression`1 expression, Func`1 condition)
Moq.Mock`1.Setup[TResult](Expression`1 expression)
这是我的测试类:
[TestClass]
public class AutobytelControllerTest
{
Mock<IUnitOfWork> mock = new Mock<IUnitOfWork>();
[TestMethod]
public void Index_Contains_All_Requests()
{
//Arrange
AutobytelController controller = new AutobytelController(mock.Object);
mock.Setup(m => m.RequestRepository.SelectAll()).Returns(new abtRequest[] {
new abtRequest {RequestID = 1, Title = "Request 1", Description = "Request Description1", UserName = "NewUser", RequestStatus = 0},
new abtRequest {RequestID = 2, Title = "Request 2", Description = "Request Description2", UserName = "ReturnUser", RequestStatus = 1}
}.AsQueryable());
//Act
abtRequest[] result = ((AutobytelHomeViewModel)controller.Index().Model).Requests.ToArray();
//Assert
Assert.AreEqual(result.Length, 2);
Assert.AreEqual("Request 1", result[0].Title);
Assert.AreEqual("Request 2", result[1].Title);
}
我有一个IUnitofWork接口和类,通用存储库接口和类以及一个实现通用存储库的请求存储库
public interface IUnitOfWork
{
RequestRepository RequestRepository { get; }
void Save();
}
public class UnitOfWorkRepository : IUnitOfWork, IDisposable
{
private AutobytelEntities context = new AutobytelEntities();
private RequestRepository requestRepository;
public RequestRepository RequestRepository
{
get
{
if (this.requestRepository == null)
{
//this.requestRepository = new GenericRepository<abtRequest>(context);
this.requestRepository = new RequestRepository(context);
}
return requestRepository;
}
}
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
internal AutobytelEntities context;
internal IObjectSet<TEntity> objectSet;
public GenericRepository(AutobytelEntities context)
{
this.context = context;
this.objectSet = context.CreateObjectSet<TEntity>();
}
public virtual IQueryable<TEntity> SelectAll()
{
return objectSet.AsQueryable();
}
public virtual TEntity Update(TEntity entity)
{
context.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Modified);
return entity;
}
public virtual void Delete(TEntity entity)
{
objectSet.DeleteObject(entity);
}
}
public class RequestRepository : GenericRepository<abtRequest>, IGenericRepository<abtRequest>
{
public RequestRepository(AutobytelEntities context) : base(context)
{ }
public virtual abtRequest SelectByUserName(string username)
{
return context.abtRequests.FirstOrDefault(i => i.UserName == username && (i.RequestStatus == 0 || i.RequestStatus == 1));
}
public virtual abtRequest SelectByRequestID(int requestID)
{
return context.abtRequests.FirstOrDefault(i => i.RequestID == requestID);
}
使用Ninject我将IUnitofwork绑定到UnitOfWork类。
如果我将无参数构造函数添加到我的请求存储库,我的错误已解决 - 但由于我不想创建新的对象上下文,我想从工作单元库中传递我的上下文。
如何解决此错误?
答案 0 :(得分:6)
我通过向RequestRepository添加一个接口并在我的工作单元中创建该接口的实例来解决此错误。我的IUnit of Work改为:
public interface IUnitOfWork
{
IRequestRepository RequestRepository { get; }
void Save();
}
我的UnitOfWork存储库内部已更改为:
private IRequestRepository requestRepository;
public IRequestRepository RequestRepository
{
get
{
if (this.requestRepository == null)
{
this.requestRepository = new RequestRepository(context);
}
return requestRepository;
}
}
答案 1 :(得分:2)
这只是伪代码,但我希望它让你更接近解决方案。你应该可以按照这些方式设置你的模拟:
//Arrange
var mockRepository = new Mock<RequestRepository>("CONSTRUCTOR ARGUMENT");
mockRepository.Setup(mr => mr.SelectAll()).Returns(new abtRequest[] {
new abtRequest {RequestID = 1, Title = "Request 1", Description = "Request Description1", UserName = "NewUser", RequestStatus = 0},
new abtRequest {RequestID = 2, Title = "Request 2", Description = "Request Description2", UserName = "ReturnUser", RequestStatus = 1}
}.AsQueryable());
mock.SetupGet(uow => uow.RequestRepository).Returns(mockRepository.Object);
AutobytelController controller = new AutobytelController(mock.Object);
上面的代码有一个构造函数参数的占位符(“CONSTRUCTOR ARGUMENT”) - 这里只提供最适合您测试场景的东西。