【发布时间】:2021-02-09 15:51:31
【问题描述】:
我建立的基础设施基于通用服务和通用存储库。现在我正在尝试编写单元测试,我遇到了一些挑战。代码如下:
IBaseRepository:
public interface IBaseRepository<T> where T : class
{
IEnumerable<T> GetAll();
T Add(T entity, bool saveChanges = true);
//more generic code
}
IServiceBase:
public interface IServiceBase<TEntity>
{
IEnumerable<TEntity> GetAll();
TEntity Create(TEntity entity);
//more generic code
}
基础存储库:
public class BaseRepository<T> : IBaseRepository<T> where T : class
{
private readonly DatabaseContext _dbContext;
public BaseRepository(DatabaseContext dbContext)
{
_dbContext = dbContext;
}
public IEnumerable<T> GetAll()
{
return _dbContext.Set<T>();
}
public T Add(T entity, bool saveChanges = true)
{
_dbContext.Set<T>().Add(entity);
if (saveChanges) _dbContext.SaveChanges();
return entity;
}
}
服务基础:
public abstract class ServiceBase<TEntity, TRepository> : IServiceBase<TEntity>
where TEntity : class
where TRepository : BaseRepository<TEntity>
{
public TRepository Repository;
public ServiceBase(BaseRepository<TEntity> rep)
{
Repository = (TRepository)rep;
}
public long Count(Expression<Func<TEntity, bool>> whereCondition)
{
return Repository.GetAll().AsQueryable().Where(whereCondition).Count();
}
}
AddressService(具体域服务):
public class AddressService : ServiceBase<Address, BaseRepository<Address>>, IAddressService
{
public AddressService(BaseRepository<Address> rep) : base(rep)
{
}
public VerifyAddress()
{
//custom logic...
}
}
测试:
public class AddressTests
{
[Fact]
public void VerifyAddress()
{
var baseRepository = new Mock<BaseRepository<Address>>();
var addressService = new AddressService(baseRepository.Object);
var test = addressService.Verify();
Assert.NotNull(test);
}
}
我得到的错误是Message: Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: Repositories.Repositories.BaseRepository. Could not find a parameterless constructor.
我知道为什么会出现此错误。原因是因为 BaseRepository 有构造函数,它期望 DatabaseContext 作为参数。
我的问题是是否可以使用这样的设置对AddressService 进行单元测试?
【问题讨论】:
-
如果向
BaseRepository添加无参数构造函数并运行测试会发生什么? -
为什么
AddressService期望BaseRepository作为输入而不是IBaseRepository?改变它应该可以解决你的问题(当然你应该模拟IBaseRepository) -
为了完成单元测试而添加无参数构造函数是一种好习惯吗?当我添加它时,它在
BaseRepository中抛出了一个System.NullReferenceException: 'Object reference not set to an instance of an object.',因为_dbContext为空,并且对数据库的每个操作都需要该属性,因为在那一侧没有任何东西被模拟 -
我在其他地方看到了问题,尝试模拟 DatabaseContext(先用接口包装它)。
标签: c# .net unit-testing asp.net-core xunit