Reputation: 9818
I have a baseService class that most of my services inherit from, which looks like this.
public abstract class BaseService<T> : IBaseService<T>
where T : class, IBaseEntity
{
protected IDataContext _context;
protected IValidator<T> _validator = null;
protected BaseService(IDataContext context)
{
_context = context;
}
protected BaseService(IDataContext context, IValidator<T> validator)
: this(context)
{
_validator = validator;
}
public virtual async Task<ICollection<T>> GetAllAsync()
{
return await _context.Set<T>().ToListAsync();
}
public virtual Task<T> GetAsync(long id)
{
return _context.Set<T>().Where(e => e.Id == id).FirstOrDefaultAsync();
}
public virtual Task<ValidationResult> ValidateAsync(T t)
{
if (_validator == null) throw new MissingFieldException("Validator does not exist for class " + t.GetType().ToString() + ". override method if no validation needed");
return _validator.ValidateAsync(t);
}
public virtual async Task<int> AddAsync(T t)
{
var results = await ValidateAsync(t);
if (!results.IsValid) {
throw new ValidationException(results.Errors);
}
if (_context.GetState(t) == EntityState.Detached)
{
_context.Set<T>().Add(t);
_context.SetState(t, EntityState.Added);
}
return await _context.SaveChangesAsync();
}
public virtual async Task<int> UpdateAsync(T updated)
{
var results = await ValidateAsync(updated);
if (!results.IsValid)
{
throw new ValidationException(results.Errors);
}
if (_context.GetState(updated) == EntityState.Detached)
{
_context.SetState(updated, EntityState.Modified);
}
return await _context.SaveChangesAsync();
}
public virtual Task<int> DeleteAsync(T t)
{
_context.SetState(t, EntityState.Deleted);
return _context.SaveChangesAsync();
}
}
Am i right in thinking that it is pointless to unit test this in every single one of my classes that implements this service? But instead, test the functionality for each test in my integration testing?
Upvotes: 3
Views: 226
Reputation: 4886
You can avoid that decision if you choose composition over inheritance, that is, instead of your services inheriting from BaseService, you create them as having IBaseService as a dependency, for example
public class MyService
{
private readonly IBaseService<SomeBaseIdentity> _service;
public MyService(IBaseService<SomeBaseIdentity> service)
{
_service = service;
}
//.... methods that use _service
}
This way you can test MyService using an isolation framework (Rhino Mocks, Moq, etc) without worrying about the actual implementation of IBaseService.
A lot has been written about this topic of choosing composition over inheritance. The great majority of which implies that it is a superior approach (mainly because it is more flexible, i.e. you can swap implementations if you use composition, whereas if you use inheritance all your derived classes are tied to the base class in the sense that changes to the base class affect all derived classes), to the point of the Java language creator saying that if he could, he would disallow it in Java.
Upvotes: 3