抽象类构造函数调用可重写方法

时间:2019-04-15 15:45:29

标签: c# moq abstract-base-class

我尝试创建一个很好的可测试存储库类以与Moq一起使用。我不想重复选择器方法(GetAllGet,...)。我的实现工作正常,但是SonarSource报告了错误RSPEC-1699,有人知道更好的实现吗?

var areas = new Area[] { ... };
var areaRepositoryMock = new Mock<BaseAreaRepository>() { CallBase = true };
areaRepositoryMock.Setup(m => m.Initialize()).Returns(areas);

基本类

public abstract class BaseAreaRepository
{
    protected Area[] _areas;

    protected BaseAreaRepository()
    {
        this._areas = this.Initialize();
    }

    public abstract Area[] Initialize();

    public Area[] GetAll()
    {
        return this._monitoredAreas;
    }

    public Area Get(int id)
    {
        return this._areas.FirstOrDefault(o => o.Id.Equals(id));
    }
}

MyAreaRepository

public class MyAreaRepository : BaseAreaRepository
{
    public override Area[] Initialize()
    {
        return //Load data from an other source
    }
}

2 个答案:

答案 0 :(得分:1)

如果您只想测试基类,那么我将创建该类的单元测试特定实现,并仅提供任何帮助程序功能来测试受保护的功能。基本上,您在测试类中以MyAreaRepository做过,但是作为private class做过。

答案 1 :(得分:1)

RSPEC-1699构造函数应仅调用不可覆盖的方法,单元测试将不包含任何内容,无论您打算如何对其进行测试,该单元测试都将保留在那里。

  

有人知道更好的实现吗?

我想提出另一种方法,以避免这种违反并使您的代码更具可测试性。

这个想法代替了base类使用组合和DI原理。

public interface IAreaContext
{
    Area[] GetAreas();
}

public class AreaRepository
{
    private IAreaContext _areaContext;

    protected BaseAreaRepository(IAreaContext areaContext)
    {
        _areaContext = areaContext;
    }

    public Area[] GetAll()
    {
        return _areaContext.GetAreas();
    }
}

然后,您可以定义IAreaContext和injext的多个实现:

public class MyAreaContext : IAreaContext
{
    public Area[] GetAreas()
    {
        return //Load data from an other source
    }
}

public class MyOtherAreaContext : IAreaContext
{
    public Area[] GetAreas()
    {
        return //Load data from an other source
    }
}

现在,当您拥有此设置存储库时,就可以轻松地测试上下文本身的不同行为。这只是一个演示想法的例子:

//Arrange
var context = new Mock<IAreaContext>();
context.Setup(m => m.GetAreas()).Verifiable();
var sut = new AreaRepository(context.Object);

//Act
var _ = sut.GetAll();

//Assert
context.Verify();