1

我尝试创建一个良好的可测试存储库类以与 Moq 一起使用。我不想重复我的选择器方法(GetAll, Get, ...)。我的实现工作正常,但 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));
    }
}

我的区域存储库

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

2 回答 2

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();
于 2019-04-16T07:10:17.380 回答
1

如果您只想测试基类,那么我将创建该类的单元测试特定实现,并提供任何帮助函数来测试受保护的函数。基本上你做了什么,MyAreaRepositoryprivate class在测试类中。

于 2019-04-15T15:53:59.363 回答