0

我正在尝试使用 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 一起应用来模拟界面?

4

1 回答 1

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以替换其具体依赖项,那么这可能只是关于静态依赖项的警示故事。

不过,您有源代码。如果你不能改变现有的类,也许你可以从现有的源代码中创建一个新的。如果有人问你为什么要复制一个现有的类,只需(委婉地)说你不想复制代码——你宁愿修复现有的类,这样它就可以测试了。

于 2019-04-30T13:09:56.743 回答