【问题标题】:Pointless unit test毫无意义的单元测试
【发布时间】:2015-04-30 03:56:08
【问题描述】:

我有一个 baseService 类,我的大多数服务都继承自该类,如下所示。

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

我是否认为在实现此服务的每个类中对它进行单元测试是没有意义的?但是,在我的集成测试中测试每个测试的功能?

【问题讨论】:

  • 真的很难说。我将测试不仅仅是围绕 LINQ 的门面的方法。断言诸如抛出的异常和实体状态之类的东西。剩下的就没有意义了.. 之后你将基本上测试 LINQ。
  • 既然方法是虚拟的,我就测试一下,因为谁知道什么时候派生类覆盖了它,但是验证失败时抛出失败,或者调用ValidateAsync失败等等。如果不是虚拟的,你只能测试一个基本涵盖所有方法的派生类。
  • 我个人会测试所有这些。为了简化该任务,您可以为每个夹具创建一个基类,使用模板方法工厂方法来创建 SUT 的具体实现,基类公共方法的测试,或者编写类似 AutoFixture 成语的东西,基本上是一个类将测试基类。
  • 将其编写为 BaseUnitTest 并从该基础测试继承单元测试以测试此功能的观点是什么?一遍又一遍地编写相同的测试似乎是浪费时间。
  • 你真的重写了这些方法吗?或者扩展,因为它似乎已经包装了所有 CRUD 的东西。如果不是,为什么要抽象。

标签: c# asp.net .net entity-framework unit-testing


【解决方案1】:

如果您选择composition over inheritance,则可以避免该决定,也就是说,您的服务不是从 BaseService 继承,而是将它们创建为具有 IBaseService 作为依赖项,例如

public class MyService 
{
  private readonly IBaseService<SomeBaseIdentity> _service;

  public MyService(IBaseService<SomeBaseIdentity> service)
  {
    _service = service;
  }

  //.... methods that use _service
}

这样您就可以使用隔离框架(Rhino Mocks、Moq 等)测试 MyService,而无需担心 IBaseService 的实际实现。

关于选择组合而不是继承的主题已经写了很多。其中绝大多数意味着它是一种优越的方法(主要是因为它更灵活,即如果您使用组合,您可以交换实现,而如果您使用继承,则所有派生类都与基类相关联,因为发生了变化到基类影响所有派生类),Java 语言创建者说如果可以,他会disallow it in Java

【讨论】:

  • 我想我会尝试这个,因为大多数时候我想在基类中使用 AddAsync 和其他函数,所以对“调用”进行单元测试似乎毫无意义。但是在我覆盖该方法的其他类中,我想对其进行单元测试。也许组合更适合这里。
  • 你将如何为 myservice 编写单元测试并说另一个名为 MyService2 的服务使用组合而不是继承?
  • 我会为每个服务编写一个单元测试,但是我会使用 IBaseService 的存根/模拟(这些名称使这变得混乱,将 IBaseService 视为依赖项,例如 IRepository)。如果您对此不熟悉,check this out.
  • 既然您提出了建议,我就采纳了您的建议。它是否正确? stackoverflow.com/questions/29653153/… 似乎可以编译,但是简单的注入器现在会在注入 IEntityBaseService 时抛出错误,我猜是因为它是通用的
猜你喜欢
  • 2011-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-11
相关资源
最近更新 更多