用Linq表达式和Lambda表示测试代码

时间:2015-06-30 19:40:08

标签: c# linq lambda

我的代码中有查询表达式,它执行以下操作:

repository.Context.AsQueryable<Option>().Where(o => o.Id == id && o.Name == "Something").Select(o => o.Id).ToArray();

我如何为上面的代码创建一个Stub?这似乎很多工作。无论如何,我可以简单地忽略传递给Where和Select方法的内容然后返回我想要返回的内容吗?

我并不关心Where和Select方法传递的内容。我只想最后返回我的硬编码项目列表。

2 个答案:

答案 0 :(得分:2)

作为选项,使用您的代码作为依赖项。这样你就可以在不触及上下文的情况下将其存根。例如:

public class OptionService : IOptionService
{
    private IRepository _repository;

    public OptionService(IRepository repository)
    {
        _repository = repository;
    }

    public int[] GetOptionsWithName(int id, string name)
    {
        _repository.Context.AsQueryable<Option>()
                           .Where(o => o.Id == id && o.Name == name)
                           .Select(o => o.Id)
                           .ToArray();
    }
}

public interface IOptionService
{
    int[] GetOptionsWithName(int id, string name);
}

IOptionService注入代码中,逻辑类似,IRepository如何注入OptionService,并在测试中存根方法GetOptionsWithName以返回您想要的任何内容。

答案 1 :(得分:1)

简短的回答是:不,因为.Where()和.Select()是扩展方法,不能被模拟。

更长的答案是:是的,因为.Where()上的.Select()IQueryable<>除了向基础查询提供商表明他们刚被调用之外什么都不做。因此,您可以在技术上为查询提供程序创建存根,并在评估之前查看它发生了什么。

但简单的答案是:我发现最好的方法是使用一个能够像查询一样运行的实际内存中表示。然后,不是尝试自己验证lambda表达式,而是测试结果数据。

var options = new[] {new Option(...)};
repositoryMock.Setup(r => r.Context).Returns(contextMock.Object);
contextMock.Setup(c => c.AsQueryable<Option>()).Returns(options.AsQueryable());

...

Assert.AreEqual(results[0], options[0].Id);

这样做的缺点是,无法测试您的方法仅使用可由查询提供程序翻译的表达式。但我一般认为这是足够好的#34;用于单元测试目的。