单元测试扩展通用服务的具体服务



我建立的基础设施是基于通用服务和通用存储库的。现在我正在尝试编写单元测试,并且遇到了一些挑战。下面是代码:

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
}

BaseRepository:

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

ServiceBase:

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作为依赖而不是IBaseRepository,这使得IBaseRepository有点多余,并将您的类紧密地耦合到特定的实现(BaseRepository)。这也意味着您对DatabaseContext有一个硬依赖,因为这是安装BaseRepository所必需的。如果您后退一步并使用IBaseRepository来实现更松散的耦合,您将同时避免对DatabaseContext的依赖,从而使单元测试更容易。

首先,更改ServiceBase的定义:

public abstract class ServiceBase<TEntity, TRepository> : IServiceBase<TEntity>
where TEntity : class
where TRepository : IBaseRepository<TEntity>
{
public TRepository Repository { get; private set; }
public ServiceBase(TRepository rep)
{
Repository = rep;
}
// ...
}

然后AddressService:

public class AddressService : ServiceBase<Address, IBaseRepository<Address>>, IAddressService
{
public AddressService(IBaseRepository<Address> rep) : base(rep)
{
}
// ...
}

现在您不再依赖于DatabaseContext,并且可以更简单地对AddressService进行单元测试(与您计划的方式相同):

public class AddressTests
{
[Fact]
public void VerifyAddress()
{
var baseRepository = new Mock<IBaseRepository<Address>>();
var addressService = new AddressService(baseRepository.Object);            
var test = addressService.Verify();
Assert.NotNull(test);
}
}

最新更新