从LLBLGen创建静态扩展方法的最小起订量

时间:2019-04-30 10:10:27

标签: c# unit-testing moq extension-methods llblgen

我正在尝试使用Moq从LLBLGen的 IDataAccessAdapter 接口模拟扩展方法。这是 FetchQueryAsync 扩展方法。

这样做给了我我无法模拟静态扩展方法的错误。但是没有办法我可以更改代码。因此,我尝试创建包装器类,但由于不知道如何应用它,因此我也没有成功。

在Fetch方法中,我希望FetchQueryAsync返回测试期间指定的对象,而不实际执行查询。

public class QueryHandler
{
    private IDataAccessAdapterProvider dataAccessAdapterProvider;
    public QueryHandler(IDataAccessAdapterProvider provider)
    {
        this.dataAccessAdapterProvider = provider;
    }

    private async Task<T> Fetch(DynamicQuery<T> query)
    {
        using (IDataAccessAdapter adapter = dataAccessAdapterProvider.Provide()
        {
            result = await adapter.FetchQueryAsync(query)
        }
    }
}

public class DataAccessAdapterProvider : IDataAccessAdapterProvider
{
    public IDataAccessAdapter Provide()
    {
    var adapter = new DataAccessAdapter();
    return adapter;
    }
}

所以在我的单元测试中,我有这个:

List<int> il = new List<int>();

Mock<IDataAccessAdapterProvider> mock = new Mock<IDataAccessAdapterProvider>();

mock.Setup(m => m.Provide()
  .FetchQueryAsync<int>(It.IsAny<DynamicQuery<int>>()))
  .ReturnsAsync(il);

但是这不起作用,因为它不受支持。 所以我尝试将这种方法包装起来。

interface IWrap
{
    Task<List<TElement>> FetchQueryAsync<TElement>(IDataAccessAdapter adapter, DynamicQuery<TElement> query);
}

public class Wrap : IWrap
{
    public async Task<List<TElement>> FetchQueryAsync<TElement>(IDataAccessAdapter adapter, DynamicQuery<TElement> query)
    {
        return await adapter.FetchQueryAsync(query);
    }
}

如何使用带有Moq的包装器来模拟界面?

1 个答案:

答案 0 :(得分:2)

您从扩展方法开始,然后创建了IWrap接口以及使用该扩展方法的实现。太完美了。

现在您所需要做的就是将其注入您的类中,就像已经注入IDataAccessAdapterProvider一样:

public class QueryHandler
{
    private readonly IDataAccessAdapterProvider _dataAccessAdapterProvider;
    private readonly IWrap _wrap; //I'm assuming you'll want a different name.

    public QueryHandler(IDataAccessAdapterProvider provider, IWrap wrap)
    {
        _dataAccessAdapterProvider = provider;
        _wrap = wrap;
    }

(我在那儿应用了一个通用约定。在字段名前加下划线-_wrap-表示字段和构造函数参数具有不同的名称,因此您无需指定this.wrap。另外,当人们在其他地方看到下划线时,他们会知道这是一个字段。)

现在您可以模拟界面:

var mock = new Mock<IWrap>();
var returnedFromMock = new List<int> { 1, 2, 3 };
mock.Setup(x => x.FetchQueryAsync<int>(It.IsAny<IDataAccessAdapter>(), It.IsAny<DynamicQuery<int>>()))
    .ReturnsAsync(returnedFromMock);

您提到无法更改代码。我不确定您不能更改哪个部分,但是如果您不能更改QueryHandler来替换其具体的依赖项,那么这可能只是关于静态依赖项的警告。

不过,您有源代码。如果您不能更改现有的类,则可以仅根据现有的源代码创建一个新的类。如果有人问为什么您要复制现有的类,只需(以句法)说您不想复制代码-您宁可修复现有的类以使其可测试。